Atividade 01

Professor : João Batista M. Pereira

Aluno : Marcel Quintela

O conjunto de dados a ser analisado corresponde a registros públicos de vendas de casas feitas de maio de 2014 a maio de 2015 no Condado de King, no estado de Washington, EUA.

O banco de dados está dividido em dois arquivos: kchousing1.csv e kchousing2.csv. No primeiro arquivo, as variáveis são:

  • id - identifcação única da casa vendida;
  • date - data da venda;
  • price - preço da venda;
  • bedrooms - quantidade de quartos;
  • bathrooms - quantidade de banheiros, em que .5 corresponde a banheiro sem chuveiro;
  • sqft living - pés quadrados do interior da casa;
  • sqft lot - pés quadrados do terreno;
  • floors - quantidade de andares;
  • waterfront - 1, se casa é à beira-mar e 0, caso contrário;
  • view - um índice de 0 a 4 indicando a qualidade da visão da propriedade;
  • condition - um índice de 0 a 5 indicando a condição do apartamento;
  • date2 - data da venda (\ano-mês").

No segundo arquivo as variaveis são:

  • id - identificação única da casa vendida;

  • date - data da venda;

  • grade - um índice de 1 a 13, em que:

    • 1-3 corresponde a um baixo nível de construção e design;
    • 7 corresponde a um nível médio de construção e design e
    • 11-13 corresponde a um alto nível de construção e design
  • sqft above - pés quadrados do interior da casa acima do nível do solo;

  • sqft basement - pés quadrados do interior da casa abaixo do nível do solo;

  • yr_built - ano em que a casa começou a ser construída;

  • yr_renovated - ano da última reforma da casa;

  • zipcode - código postal da casa;

  • lat - latitude;

  • long - longitude;

  • sqft living15 - pés quadrados do interior das 15 casas mais próximas;

  • sqft lot15 - pés quadrados do terreno das 15 casas mais próximas.

Orientações para cosntrução da Atividade1

Questão 01

Importe as bases de dados nos arquivos para o R e junte-as em um único data frame com todos os registros e todas as variáveis. Lembre-se que as linhas correspondem aos registros de vendas e uma casa pode ser vendida mais de uma vez.

Escolha pelo menos três variáveis do banco de dados e faça uma análise exploratória. Utilize gráficos tais como histogramas, box-plots, gráfico de barras e/ou gráfico de setores. Para as variáveis quantitativas, pode-se também calcular algumas medidas resumo tais como média, mediana, desvio padrão.

Importando dados

house1<-read.csv("kc_housing_1.csv",sep=",")
head(house1)
##           id            date   price bedrooms bathrooms sqft_living sqft_lot
## 1 7129300520 20141013T000000  221900        3      1.00        1180     5650
## 2 6414100192 20141209T000000  538000        3      2.25        2570     7242
## 3 5631500400 20150225T000000  180000        2      1.00         770    10000
## 4 2487200875 20141209T000000  604000        4      3.00        1960     5000
## 5 1954400510 20150218T000000  510000        3      2.00        1680     8080
## 6 7237550310 20140512T000000 1225000        4      4.50        5420   101930
##   floors waterfront view condition   date2
## 1      1          0    0         3 2014-10
## 2      2          0    0         3 2014-12
## 3      1          0    0         3 2015-02
## 4      1          0    0         5 2014-12
## 5      1          0    0         3 2015-02
## 6      1          0    0         3 2014-05
house2<-read.csv("kc_housing_2.csv",sep=",")
head(house2)
##           id            date grade sqft_above sqft_basement yr_built
## 1 7129300520 20141013T000000     7       1180             0     1955
## 2 6414100192 20141209T000000     7       2170           400     1951
## 3 5631500400 20150225T000000     6        770             0     1933
## 4 2487200875 20141209T000000     7       1050           910     1965
## 5 1954400510 20150218T000000     8       1680             0     1987
## 6 7237550310 20140512T000000    11       3890          1530     2001
##   yr_renovated zipcode     lat     long sqft_living15 sqft_lot15
## 1            0   98178 47.5112 -122.257          1340       5650
## 2         1991   98125 47.7210 -122.319          1690       7639
## 3            0   98028 47.7379 -122.233          2720       8062
## 4            0   98136 47.5208 -122.393          1360       5000
## 5            0   98074 47.6168 -122.045          1800       7503
## 6            0   98053 47.6561 -122.005          4760     101930

Mesclando os dataframes importados em único dataframe usando como chave o “ID da venda” e a “data da venda”, criando assim o banco de dados das operações de venda e caracteristicas das casas.

vendas<-merge(house1,house2,by=c("id","date"))
#checando os tamanhos dos data frames
dim(house1)
## [1] 21613    12
dim(house2)
## [1] 21613    12
dim(vendas)
## [1] 21613    22
names(house1)
##  [1] "id"          "date"        "price"       "bedrooms"    "bathrooms"  
##  [6] "sqft_living" "sqft_lot"    "floors"      "waterfront"  "view"       
## [11] "condition"   "date2"
names(house2)
##  [1] "id"            "date"          "grade"         "sqft_above"   
##  [5] "sqft_basement" "yr_built"      "yr_renovated"  "zipcode"      
##  [9] "lat"           "long"          "sqft_living15" "sqft_lot15"
names(vendas)
##  [1] "id"            "date"          "price"         "bedrooms"     
##  [5] "bathrooms"     "sqft_living"   "sqft_lot"      "floors"       
##  [9] "waterfront"    "view"          "condition"     "date2"        
## [13] "grade"         "sqft_above"    "sqft_basement" "yr_built"     
## [17] "yr_renovated"  "zipcode"       "lat"           "long"         
## [21] "sqft_living15" "sqft_lot15"
head(vendas)
##           id            date  price bedrooms bathrooms sqft_living sqft_lot
## 1    1000102 20140916T000000 280000        6       3.0        2400     9373
## 2    1000102 20150422T000000 300000        6       3.0        2400     9373
## 3  100100050 20141112T000000 275000        3       1.0        1320    11090
## 4 1001200035 20150306T000000 272450        3       1.0        1350     7973
## 5 1001200050 20140923T000000 259000        4       1.5        1260     7248
## 6 1003000175 20141222T000000 221000        3       1.0         980     7606
##   floors waterfront view condition   date2 grade sqft_above sqft_basement
## 1    2.0          0    0         3 2014-09     7       2400             0
## 2    2.0          0    0         3 2015-04     7       2400             0
## 3    1.0          0    0         3 2014-11     7       1320             0
## 4    1.5          0    0         3 2015-03     7       1350             0
## 5    1.5          0    0         5 2014-09     7       1260             0
## 6    1.0          0    0         3 2014-12     7        980             0
##   yr_built yr_renovated zipcode     lat     long sqft_living15 sqft_lot15
## 1     1991            0   98002 47.3262 -122.214          2060       7316
## 2     1991            0   98002 47.3262 -122.214          2060       7316
## 3     1955            0   98155 47.7748 -122.304          1320       8319
## 4     1954            0   98188 47.4323 -122.292          1310       7491
## 5     1955            0   98188 47.4330 -122.292          1300       7732
## 6     1954            0   98188 47.4356 -122.290           980       8125
rm(house1,house2) #Liberando memória: removendo os dados originais  

Análise Exploratória

#Extração das variaveis de estudo
house.1<-vendas[,c(3,4,5,6,10,13)]

#Ajute das variáveis de preço
house.1$price<-house.1$price/1000

nomes<-c("Preço da Casa (x US$1.000)","Nº de Quartos", "Nº de Banheiros","Interior da Casa (ft²)","Visão da Propriedade","Nível de Construção e Design")
#Resumos
EstDescri=function(x) { #função que retorna as resumo descritivo das variáveis
  c(NumObs    = length(x),
    Maximo    = max(x, na.rm=T),
    Minimo    = min(x, na.rm=T),
    Amplitude = max(x, na.rm=T)-min(x, na.rm=T),
    Media     = mean(x, na.rm=T),
    #Mediana   = median(x, na.rm=T),
    Q         = quantile(x,na.rm=T)[2],
    Q         = quantile(x,na.rm=T)[3],
    Q         = quantile(x,na.rm=T)[4],
    Variancia = var(x, na.rm=T),
    DesPadrao = sd(x, na.rm=T),
    CV        = 100* sd(x, na.rm=T)/mean(x, na.rm=T),
    Iqr       = IQR(x, na.rm=T), # Desvio Interquartilico
    Ass       = 3*(mean(x, na.rm=T)- median(x, na.rm=T))/sd(x, na.rm=T),
    Cur       = IQR(x, na.rm=T)/(2*(quantile(x,.90,na.rm=T)-quantile(x,.10,na.rm=T)))
  )
}

Resultados<- data.frame(EstDescri(house.1[,1]))
names(Resultados)[1]<-names(house.1)[1]

for (x in 2:length(house.1)){
  Resultados<-cbind(Resultados, EstDescri(house.1[,x]))
  names(Resultados)[x]<-names(house.1)[x]
}
names(Resultados)<-nomes

knitr::kable(Resultados,digits = 2,format.args = list(scientific = FALSE),
             caption = "Resumo descritivo das variáveis de estudo")
Resumo descritivo das variáveis de estudo
Preço da Casa (x US$1.000) Nº de Quartos Nº de Banheiros Interior da Casa (ft²) Visão da Propriedade Nível de Construção e Design
NumObs 21613.00 21613.00 21613.00 21613.00 21613.00 21613.00
Maximo 7700.00 33.00 8.00 13540.00 4.00 13.00
Minimo 75.00 0.00 0.00 290.00 0.00 1.00
Amplitude 7625.00 33.00 8.00 13250.00 4.00 12.00
Media 540.09 3.37 2.11 2079.90 0.23 7.66
Q.25% 321.95 3.00 1.75 1427.00 0.00 7.00
Q.50% 450.00 3.00 2.25 1910.00 0.00 7.00
Q.75% 645.00 4.00 2.50 2550.00 0.00 8.00
Variancia 134782.38 0.87 0.59 843533.68 0.59 1.38
DesPadrao 367.13 0.93 0.77 918.44 0.77 1.18
CV 67.98 27.59 36.42 44.16 327.06 15.35
Iqr 323.05 1.00 0.75 1123.00 0.00 1.00
Ass 0.74 1.20 -0.53 0.55 0.92 1.68
Cur.90% 0.25 0.25 0.19 0.26 NaN 0.17

Numa análise preliminar, pode-se afirmar a grande amplitude nos Preços de Vendas das casa e no Interior da Casa (ft²). O custo médio das casas no recorte foi de US$540 Mil.Quanto as caracteristicas das casas, o nº de banheiros maximo registrado com 33, chama a atenção visto que as demais medidas separatrizes sugerem que a casa com maior numero de quartos não supere muito em 4 quartos.

Gráficos

#Gráficos conjugados histograma e boxplot
layout(mat = matrix(c(1:12),4,3, byrow=TRUE),  height = c(rep(c(0.2,0.7),2)))
# construção do grid de impressão 3 linhas x 4 colunas

for (i in seq(1,4,by=3)){ #linhas de impressão para cada par de gráficos

  par(mar=c(0,4, 0, 1))   #limites das margensdos box-plots
  for (i2 in i:(i+2)){    #gerando os box-plots
    boxplot(house.1[,i2],xlab=nomes[i2],col="light blue",outcol="red",
            horizontal=TRUE, xaxt="n", frame=F)
  }
  par(mar=c(5,4,0,1))     #limites das margens dos histogramas
  for(i3 in i:(i+2)){     #gerando os histogramas
    hist(house.1[,i3],xlab=nomes[i3],ylab="Densidade",
         main="",col="light blue",prob=TRUE)
    curve(dnorm(x,mean(house.1[,i3], na.rm=T),sd(house.1[,i3], na.rm=T)),add=T, col="red")
  }
}

o painel da combinação do histograma e box-plot, apresenta um panorama geral das variáveis selecionadas. De maneira geral, a presença de consideráveis de valores discrepantes ganha destaque. Porém, tal resumo gráfico não se mostra tão adequado para variáveis qualitativas (categóricas) como a Visão da Propriedade. É conveniente uma avaliação especifica para variáveis quantitativas e qualitativas.

# Boxplots 
layout(mat = matrix(c(1:4),2,2, byrow=TRUE),  height = c(rep(c(0.2,0.7),2)))
par(mfrow=c(2,4),mar=c(4,4,3,2))

for(i in 1:(length(house.1)-2)){
  out<-boxplot.stats(house.1[,i])$out #+/- 1.58 IQR/sqrt(n)
  out_ind <- which(house.1[,i] %in% c(out))
  
  boxplot(house.1[,i],ylab=nomes[i],col="light blue",frame=F, outcol="red")
  mtext("Outlires (+)", side=1,line=0.5, at=0.7, cex = 0.6) 

  boxplot(house.1[-out_ind,i],ylab=nomes[i],col="light blue", frame=F)
  mtext("Outlires ( - ) *", side=1,line=0.5, at=0.7, cex = 0.6) 
  
  
}
par(oma=c(1,1,1.1,1),new=T,font=2,cex=0.5)
mtext(outer=TRUE,paste("Boxplots das variáveis avaliadas"),side=3)
mtext(outer=TRUE,paste("* Principais outliers removidos pelo método de Interválos interquartílico [+/-1.58 IQR/sqrt(n)]"),side=1, cex=0.8)

Os box-plots mostram a presença de muitas informações discrepantes, sugerindo uma avaliação mais aprofundada sobre a natureza destas com a possibilidade de remoção ou tratamento. No entanto, para este estudo, serão mantidos todos os dados originais.

#Ajuste da variável visão da propriedade
house.1<-cbind(house.1,view.f=house.1$view)
house.1$view.f<-factor(house.1$view.f, levels = c("0","1","2","3","4"))

#Ajuste da variável Nível de Construção e Design
house.1<-cbind(house.1,grade.f=house.1$grade)
house.1$grade.f[(house.1$grade %in% c(1:3))]<-"Low"
house.1$grade.f[(house.1$grade %in% c(4:6))]<-"Low-Med"
house.1$grade.f[(house.1$grade==7)]<-"Med"
house.1$grade.f[(house.1$grade %in% c(8:10))]<-"Med-High"
house.1$grade.f[(house.1$grade %in% c(11:13))]<-"High"
house.1$grade.f<-factor(house.1$grade.f, levels = c("Low","Low-Med","Med","Med-High", "High"))
#graficos das variaveis categóricas
par(mfrow = c(1,2))

x<-xtabs(~view.f,data = house.1)
barplot(x,
        ylab = "Frequência absoluta",
        xlab = nomes[5],
        ylim = c(0,max(x)*1.1),#lim sup 10% a+ p/ max para melhor visualização
        col=hcl.colors(length(x), "Green-Orange"))

x<-xtabs(~grade.f,data = house.1)
barplot(x,
        ylab = "Frequência absoluta",
        xlab = nomes[6],
        ylim = c(0,max(x)*1.1),
        col=hcl.colors(length(x), "Red-Green"),
        cex.names = 0.6,
        las=3)

par(oma=c(1,1,1.1,1),new=T,font=2,cex=0.5)
mtext(outer=TRUE,paste("Gráficos de Barras das Variáveis Categóricas"),side=3)

#gray.colors(n)
#hcl.pals() nomes das pallets

As variáveis categóricas mostram que a grande maioria da propriedade tem baixo nível na qualidade da visão, ao passo que o nível das construções são predominantemente consideradas como nível médio ou médio-alto.

#limpando a mémoria
rm(Resultados, EstDescri,out, out_ind,x,house.1,i,i2,i3)

Questão 02

Para as variáveis quantitativas, calcule a matriz de correlação e faça um gráco em que se possa facilmente visualizar as correlações entre as variáveis. Em seguida, faça diagramas de dispersão para os dois pares de variáveis mais correlacionados.

Matriz de Correlação

COR<-cor(vendas[,-c(1,2,12)])
# Kable é um gerador de tabela com formatação amigavel para saidas html
knitr::kable(COR,digits = 2,format.args = list(scientific = FALSE),
             caption = "Correlação entre as variáveis do banco de dados")
Correlação entre as variáveis do banco de dados
price bedrooms bathrooms sqft_living sqft_lot floors waterfront view condition grade sqft_above sqft_basement yr_built yr_renovated zipcode lat long sqft_living15 sqft_lot15
price 1.00 0.31 0.53 0.70 0.09 0.26 0.27 0.40 0.04 0.67 0.61 0.32 0.05 0.13 -0.05 0.31 0.02 0.59 0.08
bedrooms 0.31 1.00 0.52 0.58 0.03 0.18 -0.01 0.08 0.03 0.36 0.48 0.30 0.15 0.02 -0.15 -0.01 0.13 0.39 0.03
bathrooms 0.53 0.52 1.00 0.75 0.09 0.50 0.06 0.19 -0.12 0.66 0.69 0.28 0.51 0.05 -0.20 0.02 0.22 0.57 0.09
sqft_living 0.70 0.58 0.75 1.00 0.17 0.35 0.10 0.28 -0.06 0.76 0.88 0.44 0.32 0.06 -0.20 0.05 0.24 0.76 0.18
sqft_lot 0.09 0.03 0.09 0.17 1.00 -0.01 0.02 0.07 -0.01 0.11 0.18 0.02 0.05 0.01 -0.13 -0.09 0.23 0.14 0.72
floors 0.26 0.18 0.50 0.35 -0.01 1.00 0.02 0.03 -0.26 0.46 0.52 -0.25 0.49 0.01 -0.06 0.05 0.13 0.28 -0.01
waterfront 0.27 -0.01 0.06 0.10 0.02 0.02 1.00 0.40 0.02 0.08 0.07 0.08 -0.03 0.09 0.03 -0.01 -0.04 0.09 0.03
view 0.40 0.08 0.19 0.28 0.07 0.03 0.40 1.00 0.05 0.25 0.17 0.28 -0.05 0.10 0.08 0.01 -0.08 0.28 0.07
condition 0.04 0.03 -0.12 -0.06 -0.01 -0.26 0.02 0.05 1.00 -0.14 -0.16 0.17 -0.36 -0.06 0.00 -0.01 -0.11 -0.09 0.00
grade 0.67 0.36 0.66 0.76 0.11 0.46 0.08 0.25 -0.14 1.00 0.76 0.17 0.45 0.01 -0.18 0.11 0.20 0.71 0.12
sqft_above 0.61 0.48 0.69 0.88 0.18 0.52 0.07 0.17 -0.16 0.76 1.00 -0.05 0.42 0.02 -0.26 0.00 0.34 0.73 0.19
sqft_basement 0.32 0.30 0.28 0.44 0.02 -0.25 0.08 0.28 0.17 0.17 -0.05 1.00 -0.13 0.07 0.07 0.11 -0.14 0.20 0.02
yr_built 0.05 0.15 0.51 0.32 0.05 0.49 -0.03 -0.05 -0.36 0.45 0.42 -0.13 1.00 -0.22 -0.35 -0.15 0.41 0.33 0.07
yr_renovated 0.13 0.02 0.05 0.06 0.01 0.01 0.09 0.10 -0.06 0.01 0.02 0.07 -0.22 1.00 0.06 0.03 -0.07 0.00 0.01
zipcode -0.05 -0.15 -0.20 -0.20 -0.13 -0.06 0.03 0.08 0.00 -0.18 -0.26 0.07 -0.35 0.06 1.00 0.27 -0.56 -0.28 -0.15
lat 0.31 -0.01 0.02 0.05 -0.09 0.05 -0.01 0.01 -0.01 0.11 0.00 0.11 -0.15 0.03 0.27 1.00 -0.14 0.05 -0.09
long 0.02 0.13 0.22 0.24 0.23 0.13 -0.04 -0.08 -0.11 0.20 0.34 -0.14 0.41 -0.07 -0.56 -0.14 1.00 0.33 0.25
sqft_living15 0.59 0.39 0.57 0.76 0.14 0.28 0.09 0.28 -0.09 0.71 0.73 0.20 0.33 0.00 -0.28 0.05 0.33 1.00 0.18
sqft_lot15 0.08 0.03 0.09 0.18 0.72 -0.01 0.03 0.07 0.00 0.12 0.19 0.02 0.07 0.01 -0.15 -0.09 0.25 0.18 1.00

A matriz e correlação é uma ótima manaira de analizar os níveis associação linear entre pares de variáveis. Póem matizes com grandes números de váriáveis, podem não ser tão claras.

#instalação de pacote necessário para ilustração da matriz de correlação
if (!require("corrplot")) install.packages("corrplot", dependencies = TRUE, INSTALL_opts = '--no-lock')
## Loading required package: corrplot
## corrplot 0.84 loaded
library(corrplot)
#ilustração da matrix de correlações de maneira mais amigável
corrplot(COR, method = "square", type="upper")

rm(COR)

O correlograma produzido pelo “corrplor”, evidencia associações consideráveis entre: price e bathrooms, sqft_living, grade, sqft_above e sqft_lot15; sqft_living e grade, sqft_above e sqft_lot15. As variáveis que representam áreas tem altos niveis de associação, pois algumas delas são composição de outras. Desta forma, estas variáveis podem ser consideradas autocorrelacionadas.

Gráficos

# par de maior correlação
plot(sqft_living ~ sqft_above,
     data  = vendas,
     main = "Dispressão \n Interior da casa X Interior da casa acima do nível do solo ",
     cex.main = 0.9,
     xlab = "Interior da casa acima do nível do solo (ft²)",
     ylab = "Interior da casa (ft²)",
     xlim = c(0,14000),
     pch  = 21,
     cex  = 0.8,
     col  = "black",
     bg   = "gray",
     frame= FALSE)
grid()
abline(coef = c(0,1), col="red")

O gráfico acima mostra a disperssão dos dados entra as duas variavais de maior correlação: a área do Interior da casa acima do nível do solo (ft²) e Interior da casa (ft²). A diagonal traçada em vermelho, mostra que a relação interior/acima será pelo menos 1. - As construções plotadas sobre a diagonal mostra que toda a construção está acima do solo e não temdo nada construído abaixo do solo; - Quanto mais afastado o ponto acima da diagonal se afasta dela maior a área contruída no subsolo; - Nenhuma construção é totalmente no subsolo.

Questão 03

Verifique grafiamente a associação entre o preço e pelo menos três outras variáveis do banco de dados. Investigue a melhor forma de visualização: gráco de dispersão, box-blots.

Disperssão: Preço X Interior da Casa (by Beira-mar)

#Disperssão 01
cols<-hcl.colors(length(levels(as.factor(vendas$waterfront))), "Green-Orange")
  
plot(price/1000 ~ sqft_living,
     data = vendas,
     main = "Preço X Interior da Casa \n (by Beira-mar)",
     xlab = "Interior da casa (ft²)",
     ylab = "Preço (US$ *1.000)",
     cex.main = 0.9,
     bg = cols,
     pch = 21,
     cex=0.8,
     frame= F)

legend("top",
       pch = 21,
       lty = 0,
       col = "black",
       pt.bg = cols,
       legend = c("Outros locais","Baira-mar"),
       bty = "n")
grid()

rm(cols)

É possível observar uma relação positiva entre o preço de venda e o interior da casa. No entanto, não é possível visualizar alguma relação entre elas e a posição da construção a beira-mar.

Disperssão: Preço X Número de Quartos (by Condição do Apartamento)

#Disperssão 01
cols<-hcl.colors(length(levels(factor(vendas$condition))), "inferno")
  
plot(price/1000 ~ bedrooms,
     data = vendas,
     main = "Preço X Nº de Quartos \n (by Condição do Apartamento)",
     xlab = "Nº de Quartos",
     ylab = "Preço (US$ *1.000)",
     cex.main = 0.9,
     bg = cols,
     pch = 21,
     cex=0.8,
     frame= F)
legend("top",
       pch = 21,
       lty = 0,
       col = "black",
       pt.bg = cols,
       legend = levels(factor(vendas$condition)),
       bty = "n")
grid()

rm(cols)

A disperssão de preço de venda x nº de quartos associada a condição da Cosntrução não mostra nhenuma relação entre elas .

Box-Plot

x<- data.frame(Indice=c(4,5,10,13,9),Nomes=(c(nomes[c(2,3,5,6)],"Beira-Mar")))
par(mfrow = c(2,3))

for(i in 1:length(x$Indice)){
  boxplot((vendas$price/1000) ~ vendas[,x$Indice[i]],
          xlab = x$Nomes[i],
          ylab = "Preço de Venda (US$ x1.000)",
          col  = "light blue",
          frame = FALSE, 
          outcol= "red")
}
rm(x)

As distribuições dos preços por grupos das variáveis nas representações dos box-plot, sedo possível notar oma relação positiva entre o preço e as medianas dos grupos da variáveis.

Questão 04

Agrupe os dados por data (mês e ano) e calcule a média do preço para cada mês. Em seguida, faça um gráfico de linha com a variação do preço ao longo do tempo.

A partir dos preços e pés quadrados do interior da casa, calcule, para cada registro, o preço médio do pé quadrado. Em seguida, faça um gráco de linha com a variação do preço médio ao longo do tempo.

Preparação e Ajustes

# instalação de pacotes para criação de gráfico temporal

.packages = c("dygraphs", "xts")# Lista de bibliotecas necessárias

# Instalar (caso ainda não tenha sido instalado)
.inst <- .packages %in% installed.packages()
if(length(.packages[!.inst]) > 0) install.packages(.packages[!.inst],dependencies = TRUE)

# Carregando bibliotecas
lapply(.packages, require, character.only=TRUE)

Preços de Venda por Data

#Arupando a média do preço de venda por date2() 
x <- aggregate(vendas$price/1000, by = list(vendas$date2), FUN=mean)

#criando a sequencia de datas para auxiliar no gráfico.
x <-cbind(x,time=seq(from= as.Date("01/05/2014","%d/%m/%Y"),
                     to  = as.Date("01/05/2015","%d/%m/%Y"),
                     by  = "month"))

# Necessário trnasformar em formato "xts" para poder usar o dygraph
graf <- xts(x = x$x, order.by = x$time)

dygraph(graf,
        main="Comportamento da Média de Preços de Venda",
        ylab="Preços de Venda (US$ *1.000)",
        xlab="Meses")
rm(x,graf)

A média de preços dos imóveis teve um comportamente de queda até fev/2015, quando retomou uma subida muito rápida.

Preço Médio por ft² do Interior da Casa

# criando variável preço por ft² constrída
vendas <- cbind(vendas, price_ft2 = (vendas$price/vendas$sqft_living))
#Arupando a média do preço/ft² date2() 
x <- aggregate(vendas$price_ft2, by = list(vendas$date2), FUN=mean)

#criando a sequencia de datas para auxiliar no gráfico.
x <-cbind(x,time=seq(from= as.Date("01/05/2014","%d/%m/%Y"),
                     to  = as.Date("01/05/2015","%d/%m/%Y"),
                     by  = "month"))

# Necessário trnasformar em formato "xts" para poder usar o dygraph
graf <- xts(x = x$x, order.by = x$time)

dygraph(graf,
        main="Comportamento da Média de Preços/ft² do Interior da Casa",
        ylab="Preços de Venda/ft²",
        xlab="Meses")
rm(x,graf)

o preço médio por ft² tem um movimento suave de queda no periodo de Mai/2014 a Dez/2014, onde foi registrado o menor patamar do preço. A partir de então um comportamento de valorização rápida superando os patamares anterioes no 3º mes subida.

Questão 05

Calcule os quartis do preço (valores que dividem os preços em quatro faixas, cada um com 25% dos registros). Verifique em que faixa cada preço do banco de dados se encontra e associe a ele um cor diferente. Em seguida, faça um gráco em três dimensões com a latitude, longitude e o preço (com as cores correspondentes à sua respectiva faixa).

Preparação e Ajustes

## Loading required package: scatterplot3d
# classificação dos quartis de preços de venda
vendas<-cbind(vendas,
              price.q = with(vendas,
                             cut(price,
                                 breaks = quantile(price,
                                                   probs=seq(0,1, by=0.25),
                                                   na.rm=TRUE),
                                 labels = 1:4,
                                 include.lowest=TRUE)))

Gráfico 3D Estático

#Scaterplot 3D

#Paleta de cores
cols<-hcl.colors(length(levels(vendas$price.q)), "PuOr")

with(vendas,{
  scatterplot3d(lat,long,price/1000,
                main = "3-D Scaterplot",
                xlab="Latitude",
                zlab="Preço de Venda (US$ x1.000)",
                ylab="Longitude",
                type="p",
                lty.hplot=2,
                scale.y=.5,
                box=T,
                color=cols[price.q],
                pch=16,
                angle=45)
})

A dispersão em 3 dimensões apresenta uma visualização planos na malha de latitude e logitude para cada nível dos quartis dos preços de vendas. Estes planos poderiam ser mais bem identificados com o isolamento dos maiores preços, os quais distorcem o eixo causando uma sobreposição visual dos pontos.

Gráfico 3D Interativo

## Loading required package: rgl
## Warning: package 'rgl' was built under R version 4.0.4
# Retirada de uma amostra aleatória de 1000 casas para ilustrar o grafico interativo 
vendas.1<-vendas[sample(1:nrow(vendas),1000,replace=F),]

cols<-hcl.colors(length(levels(vendas$price.q)), "PuOr")
# Grafico interativo simples
plotids <- with(vendas.1, plot3d(lat,long,(price/1000),
 type="s", col=cols[price.q],size=1))
rglwidget(elementId = "plot3drgl")
#grafico interativo mais elaborado com a possibilidade de exibição dos elementos
clear3d() # Remove the earlier display
#rm(axesid)
# Ciração dos elementos para o objeto grafico3d de acordo com os elementos da biblioteca rgl
Q1 <- with(subset(vendas.1, price.q == 1),
           spheres3d(lat,long,(price/1000),
                     col=cols[price.q],
                     radius = 50))

Q2 <- with(subset(vendas.1, price.q == 2),
           spheres3d(lat,long,(price/1000),
                     col=cols[price.q],
                     radius = 50))

Q3 <- with(subset(vendas.1, price.q == 3),
           spheres3d(lat,long,(price/1000),
                     col=cols[price.q],
                     radius = 50))

Q4 <- with(subset(vendas.1, price.q == 4),
           spheres3d(lat,long,(price/1000),
                     col=cols[price.q],
                     radius = 50))

#criando o objeto grafico3d, criado por plot3d ou decorate3d
axesid <- decorate3d(xlab = "Latitude", ylab = "Logitude", zlab = "Preço (x1.000)")

#incluindo os elementos no objeto grafico3d
rglwidget() %>% 
toggleWidget(ids = Q1) %>%
toggleWidget(ids = Q2) %>%
toggleWidget(ids = Q3) %>%
toggleWidget(ids = Q4) %>%
toggleWidget(ids = axesid) %>% 
asRow(last = 5) 
#número e objetos a serem apresentados recomendo que seja last=nº de elementos toggleWinget
#assim será apresentado em uma linha abaixo do gráfico

Mapa - poins group Quatil(Price)

library(leaflet)
## 
## Attaching package: 'leaflet'
## The following object is masked from 'package:xts':
## 
##     addLegend
cols<-c("orange", "lightgreen", "lightblue", "purple")

vendas.1<-cbind(vendas.1,House=paste("House ",c(1:dim(vendas.1)[1])))

printMoney <- function(x){
  format(x, digits=10, nsmall=2, decimal.mark=",", big.mark=".")
}

icone <- awesomeIcons(
  icon = 'home',
  iconColor = "white",
  library = 'ion',
  markerColor = cols[vendas.1$price.q]
)


leaflet(vendas.1) %>% 
  addTiles() %>% 
  addAwesomeMarkers(popup = with(vendas.1,
                          paste("<b>Preço: US$</b>",printMoney(price),"<br>",
                                "<b>Banheiros: </b>",bathrooms,"<br>",
                                "<b>Quartos: </b>",bedrooms)),
             icon=icone,
             label= ~House)
## Assuming "long" and "lat" are longitude and latitude, respectively

Mapa - Clusters Quartil dos Preços

vendas.2<-cbind(vendas.1,
              price.qq = with(vendas.1,
                             cut(price/1000,
                                 breaks = quantile(price/1000,
                                                   probs=seq(0,1, by=0.25),
                                                   na.rm=TRUE),
                                 #labels = 1:4,
                                 include.lowest=TRUE)))

vendas.df <- split(vendas.2, vendas.2$price.qq)

l <- leaflet() %>% addTiles()

names(vendas.df) %>%
  purrr::walk( function(df) {
    l <<- l %>%
      addMarkers(data=vendas.df[[df]],
                          lng=~long, lat=~lat,
                          label=~price.q,
                          popup = with(vendas.df[[df]],
                                       paste("<b>Preço: US$</b>",printMoney(~price),"<br>",
                                        "<b>Banheiros: </b>",~bathrooms,"<br>",
                                        "<b>Quartos: </b>",~bedrooms)),
                          group = df,
                          clusterOptions = markerClusterOptions(removeOutsideVisibleBounds = F),
                          labelOptions = labelOptions(noHide = F,
                                                       direction = 'auto'))
  })

l %>%
  addLayersControl(
    overlayGroups = names(vendas.df),
    options = layersControlOptions(collapsed = FALSE)
  )

  1. A atividade deve ser feita no R Markdown e entregue em HTML ou PDF com os códigos explicitados e as análises comentadas. Os grácos devem ser explicativos, com nomes corretos nos eixos, por exemplo↩︎

LS0tDQp0aXRsZTogIk1pbmVyYcOnw6NvIGRlIERhZG9zIg0KUHJvZmVzc29yOiBKb8OjbyBCYXRpc3RhIE0uIFBlcmVpcmENCkRpc2NpcGxpbmE6IE1pbmVyYcOnw6NvIGRlIERhZG9zDQpBbHVubzogTWFyY2VsIERhbnRhcyBkZSBRdWludGVsYQ0KRGF0YTogMDgvMDIvMjAyMQ0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiA3Mg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Kc2V0d2QoIkM6XFxVc2Vyc1xcTWFyY2VsXFxEcm9wYm94XFwwMCBDaWVuY2lhcyBkZSBEYWRvc1xcTTAyX01pbmVyYWNhb1xcQXRpdmlkYWRlc1xcQVRWMDFfTTAyX01pbmVyYWNhbyIpDQpgYGANCg0KIyBBdGl2aWRhZGUgMDENCg0KOjo6IHtzdHlsZT0idGV4dC1hbGlnbjogcmlnaHQ7IGNvbG9yOlJlZCJ9DQpQcm9mZXNzb3IgOiBKb8OjbyBCYXRpc3RhIE0uIFBlcmVpcmENCg0KQWx1bm8gOiBNYXJjZWwgUXVpbnRlbGENCjo6Og0KDQpPIGNvbmp1bnRvIGRlIGRhZG9zIGEgc2VyIGFuYWxpc2FkbyBjb3JyZXNwb25kZSBhIHJlZ2lzdHJvcyBww7pibGljb3MgZGUNCnZlbmRhcyBkZSBjYXNhcyBmZWl0YXMgZGUgbWFpbyBkZSAyMDE0IGEgbWFpbyBkZSAyMDE1IG5vIENvbmRhZG8gZGUNCktpbmcsIG5vIGVzdGFkbyBkZSBXYXNoaW5ndG9uLCBFVUEuDQoNCk8gYmFuY28gZGUgZGFkb3MgZXN0w6EgZGl2aWRpZG8gZW0gZG9pcyBhcnF1aXZvczoga2Nob3VzaW5nMS5jc3YgZQ0Ka2Nob3VzaW5nMi5jc3YuIE5vIHByaW1laXJvIGFycXVpdm8sIGFzIHZhcmnDoXZlaXMgc8OjbzoNCg0KLSAgIGlkIC0gaWRlbnRpZmNhw6fDo28gw7puaWNhIGRhIGNhc2EgdmVuZGlkYTsNCi0gICBkYXRlIC0gZGF0YSBkYSB2ZW5kYTsNCi0gICBwcmljZSAtIHByZcOnbyBkYSB2ZW5kYTsNCi0gICBiZWRyb29tcyAtIHF1YW50aWRhZGUgZGUgcXVhcnRvczsNCi0gICBiYXRocm9vbXMgLSBxdWFudGlkYWRlIGRlIGJhbmhlaXJvcywgZW0gcXVlIC41IGNvcnJlc3BvbmRlIGENCiAgICBiYW5oZWlybyBzZW0gY2h1dmVpcm87DQotICAgc3FmdCBsaXZpbmcgLSBww6lzIHF1YWRyYWRvcyBkbyBpbnRlcmlvciBkYSBjYXNhOw0KLSAgIHNxZnQgbG90IC0gcMOpcyBxdWFkcmFkb3MgZG8gdGVycmVubzsNCi0gICBmbG9vcnMgLSBxdWFudGlkYWRlIGRlIGFuZGFyZXM7DQotICAgd2F0ZXJmcm9udCAtIDEsIHNlIGNhc2Egw6kgw6AgYmVpcmEtbWFyIGUgMCwgY2FzbyBjb250csOhcmlvOw0KLSAgIHZpZXcgLSB1bSDDrW5kaWNlIGRlIDAgYSA0IGluZGljYW5kbyBhIHF1YWxpZGFkZSBkYSB2aXPDo28gZGENCiAgICBwcm9wcmllZGFkZTsNCi0gICBjb25kaXRpb24gLSB1bSDDrW5kaWNlIGRlIDAgYSA1IGluZGljYW5kbyBhIGNvbmRpw6fDo28gZG8gYXBhcnRhbWVudG87DQotICAgZGF0ZTIgLSBkYXRhIGRhIHZlbmRhIChcXGFuby1tw6pzIikuDQoNCk5vIHNlZ3VuZG8gYXJxdWl2byBhcyB2YXJpYXZlaXMgc8OjbzoNCg0KLSAgIGlkIC0gaWRlbnRpZmljYcOnw6NvIMO6bmljYSBkYSBjYXNhIHZlbmRpZGE7DQoNCi0gICBkYXRlIC0gZGF0YSBkYSB2ZW5kYTsNCg0KLSAgIGdyYWRlIC0gdW0gw61uZGljZSBkZSAxIGEgMTMsIGVtIHF1ZToNCg0KICAgIC0gICAxLTMgY29ycmVzcG9uZGUgYSB1bSBiYWl4byBuw612ZWwgZGUgY29uc3RydcOnw6NvIGUgZGVzaWduOw0KICAgIC0gICA3IGNvcnJlc3BvbmRlIGEgdW0gbsOtdmVsIG3DqWRpbyBkZSBjb25zdHJ1w6fDo28gZSBkZXNpZ24gZQ0KICAgIC0gICAxMS0xMyBjb3JyZXNwb25kZSBhIHVtIGFsdG8gbsOtdmVsIGRlIGNvbnN0cnXDp8OjbyBlIGRlc2lnbg0KDQotICAgc3FmdCBhYm92ZSAtIHDDqXMgcXVhZHJhZG9zIGRvIGludGVyaW9yIGRhIGNhc2EgYWNpbWEgZG8gbsOtdmVsIGRvDQogICAgc29sbzsNCg0KLSAgIHNxZnQgYmFzZW1lbnQgLSBww6lzIHF1YWRyYWRvcyBkbyBpbnRlcmlvciBkYSBjYXNhIGFiYWl4byBkbyBuw612ZWwgZG8NCiAgICBzb2xvOw0KDQotICAgeXJfYnVpbHQgLSBhbm8gZW0gcXVlIGEgY2FzYSBjb21lw6dvdSBhIHNlciBjb25zdHJ1w61kYTsNCg0KLSAgIHlyX3Jlbm92YXRlZCAtIGFubyBkYSDDumx0aW1hIHJlZm9ybWEgZGEgY2FzYTsNCg0KLSAgIHppcGNvZGUgLSBjw7NkaWdvIHBvc3RhbCBkYSBjYXNhOw0KDQotICAgbGF0IC0gbGF0aXR1ZGU7DQoNCi0gICBsb25nIC0gbG9uZ2l0dWRlOw0KDQotICAgc3FmdCBsaXZpbmcxNSAtIHDDqXMgcXVhZHJhZG9zIGRvIGludGVyaW9yIGRhcyAxNSBjYXNhcyBtYWlzDQogICAgcHLDs3hpbWFzOw0KDQotICAgc3FmdCBsb3QxNSAtIHDDqXMgcXVhZHJhZG9zIGRvIHRlcnJlbm8gZGFzIDE1IGNhc2FzIG1haXMgcHLDs3hpbWFzLg0KDQpPcmllbnRhw6fDtWVzIHBhcmEgY29zbnRydcOnw6NvIGRhIEF0aXZpZGFkZVteMV0NCg0KW14xXTogKkEgYXRpdmlkYWRlIGRldmUgc2VyIGZlaXRhIG5vICoqUiBNYXJrZG93bioqIGUgZW50cmVndWUgZW0NCiAgICAqKkhUTUwqKiBvdSAqKlBERioqIGNvbSBvcyBjw7NkaWdvcyBleHBsaWNpdGFkb3MgZSBhcyBhbsOhbGlzZXMNCiAgICBjb21lbnRhZGFzLiBPcyBncsOhY29zIGRldmVtIHNlciBleHBsaWNhdGl2b3MsIGNvbSBub21lcyBjb3JyZXRvcyBub3MNCiAgICBlaXhvcywgcG9yIGV4ZW1wbG8qDQoNCiMjIFF1ZXN0w6NvIDAxDQoNCkltcG9ydGUgYXMgYmFzZXMgZGUgZGFkb3Mgbm9zIGFycXVpdm9zIHBhcmEgbyAqKlIqKiBlIGp1bnRlLWFzIGVtIHVtDQrDum5pY28gKmRhdGEgZnJhbWUqIGNvbSB0b2RvcyBvcyByZWdpc3Ryb3MgZSB0b2RhcyBhcyB2YXJpw6F2ZWlzLg0KTGVtYnJlLXNlIHF1ZSBhcyBsaW5oYXMgY29ycmVzcG9uZGVtIGFvcyByZWdpc3Ryb3MgZGUgdmVuZGFzIGUgdW1hIGNhc2ENCnBvZGUgc2VyIHZlbmRpZGEgbWFpcyBkZSB1bWEgdmV6Lg0KDQpFc2NvbGhhIHBlbG8gbWVub3MgdHLDqnMgdmFyacOhdmVpcyBkbyBiYW5jbyBkZSBkYWRvcyBlIGZhw6dhIHVtYSBhbsOhbGlzZQ0KZXhwbG9yYXTDs3JpYS4gVXRpbGl6ZSBncsOhZmljb3MgdGFpcyBjb21vIGhpc3RvZ3JhbWFzLCAqYm94LXBsb3RzKiwNCmdyw6FmaWNvIGRlIGJhcnJhcyBlL291IGdyw6FmaWNvIGRlIHNldG9yZXMuIFBhcmEgYXMgdmFyacOhdmVpcw0KcXVhbnRpdGF0aXZhcywgcG9kZS1zZSB0YW1iw6ltIGNhbGN1bGFyIGFsZ3VtYXMgbWVkaWRhcyByZXN1bW8gdGFpcyBjb21vDQptw6lkaWEsIG1lZGlhbmEsIGRlc3ZpbyBwYWRyw6NvLg0KDQojIyMgSW1wb3J0YW5kbyBkYWRvcw0KDQpgYGB7ciBRMDEuMX0NCmhvdXNlMTwtcmVhZC5jc3YoImtjX2hvdXNpbmdfMS5jc3YiLHNlcD0iLCIpDQpoZWFkKGhvdXNlMSkNCg0KaG91c2UyPC1yZWFkLmNzdigia2NfaG91c2luZ18yLmNzdiIsc2VwPSIsIikNCmhlYWQoaG91c2UyKQ0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KTWVzY2xhbmRvIG9zIGRhdGFmcmFtZXMgaW1wb3J0YWRvcyBlbSDDum5pY28gZGF0YWZyYW1lIHVzYW5kbyBjb21vIGNoYXZlDQpvICJJRCBkYSB2ZW5kYSIgZSBhICJkYXRhIGRhIHZlbmRhIiwgY3JpYW5kbyBhc3NpbSBvIGJhbmNvIGRlIGRhZG9zIGRhcw0Kb3BlcmHDp8O1ZXMgZGUgdmVuZGEgZSBjYXJhY3RlcmlzdGljYXMgZGFzIGNhc2FzLg0KOjo6DQoNCmBgYHtyfQ0KdmVuZGFzPC1tZXJnZShob3VzZTEsaG91c2UyLGJ5PWMoImlkIiwiZGF0ZSIpKQ0KI2NoZWNhbmRvIG9zIHRhbWFuaG9zIGRvcyBkYXRhIGZyYW1lcw0KZGltKGhvdXNlMSkNCmRpbShob3VzZTIpDQpkaW0odmVuZGFzKQ0KDQpuYW1lcyhob3VzZTEpDQpuYW1lcyhob3VzZTIpDQpuYW1lcyh2ZW5kYXMpDQoNCmhlYWQodmVuZGFzKQ0Kcm0oaG91c2UxLGhvdXNlMikgI0xpYmVyYW5kbyBtZW3Ds3JpYTogcmVtb3ZlbmRvIG9zIGRhZG9zIG9yaWdpbmFpcyAgDQpgYGANCg0KIyMjIEFuw6FsaXNlIEV4cGxvcmF0w7NyaWENCg0KYGBge3J9DQojRXh0cmHDp8OjbyBkYXMgdmFyaWF2ZWlzIGRlIGVzdHVkbw0KaG91c2UuMTwtdmVuZGFzWyxjKDMsNCw1LDYsMTAsMTMpXQ0KDQojQWp1dGUgZGFzIHZhcmnDoXZlaXMgZGUgcHJlw6dvDQpob3VzZS4xJHByaWNlPC1ob3VzZS4xJHByaWNlLzEwMDANCg0Kbm9tZXM8LWMoIlByZcOnbyBkYSBDYXNhICh4IFVTJDEuMDAwKSIsIk7CuiBkZSBRdWFydG9zIiwgIk7CuiBkZSBCYW5oZWlyb3MiLCJJbnRlcmlvciBkYSBDYXNhIChmdMKyKSIsIlZpc8OjbyBkYSBQcm9wcmllZGFkZSIsIk7DrXZlbCBkZSBDb25zdHJ1w6fDo28gZSBEZXNpZ24iKQ0KYGBgDQoNCmBgYHtyfQ0KI1Jlc3Vtb3MNCkVzdERlc2NyaT1mdW5jdGlvbih4KSB7ICNmdW7Dp8OjbyBxdWUgcmV0b3JuYSBhcyByZXN1bW8gZGVzY3JpdGl2byBkYXMgdmFyacOhdmVpcw0KICBjKE51bU9icyAgICA9IGxlbmd0aCh4KSwNCiAgICBNYXhpbW8gICAgPSBtYXgoeCwgbmEucm09VCksDQogICAgTWluaW1vICAgID0gbWluKHgsIG5hLnJtPVQpLA0KICAgIEFtcGxpdHVkZSA9IG1heCh4LCBuYS5ybT1UKS1taW4oeCwgbmEucm09VCksDQogICAgTWVkaWEgICAgID0gbWVhbih4LCBuYS5ybT1UKSwNCiAgICAjTWVkaWFuYSAgID0gbWVkaWFuKHgsIG5hLnJtPVQpLA0KICAgIFEgICAgICAgICA9IHF1YW50aWxlKHgsbmEucm09VClbMl0sDQogICAgUSAgICAgICAgID0gcXVhbnRpbGUoeCxuYS5ybT1UKVszXSwNCiAgICBRICAgICAgICAgPSBxdWFudGlsZSh4LG5hLnJtPVQpWzRdLA0KICAgIFZhcmlhbmNpYSA9IHZhcih4LCBuYS5ybT1UKSwNCiAgICBEZXNQYWRyYW8gPSBzZCh4LCBuYS5ybT1UKSwNCiAgICBDViAgICAgICAgPSAxMDAqIHNkKHgsIG5hLnJtPVQpL21lYW4oeCwgbmEucm09VCksDQogICAgSXFyICAgICAgID0gSVFSKHgsIG5hLnJtPVQpLCAjIERlc3ZpbyBJbnRlcnF1YXJ0aWxpY28NCiAgICBBc3MgICAgICAgPSAzKihtZWFuKHgsIG5hLnJtPVQpLSBtZWRpYW4oeCwgbmEucm09VCkpL3NkKHgsIG5hLnJtPVQpLA0KICAgIEN1ciAgICAgICA9IElRUih4LCBuYS5ybT1UKS8oMioocXVhbnRpbGUoeCwuOTAsbmEucm09VCktcXVhbnRpbGUoeCwuMTAsbmEucm09VCkpKQ0KICApDQp9DQoNClJlc3VsdGFkb3M8LSBkYXRhLmZyYW1lKEVzdERlc2NyaShob3VzZS4xWywxXSkpDQpuYW1lcyhSZXN1bHRhZG9zKVsxXTwtbmFtZXMoaG91c2UuMSlbMV0NCg0KZm9yICh4IGluIDI6bGVuZ3RoKGhvdXNlLjEpKXsNCiAgUmVzdWx0YWRvczwtY2JpbmQoUmVzdWx0YWRvcywgRXN0RGVzY3JpKGhvdXNlLjFbLHhdKSkNCiAgbmFtZXMoUmVzdWx0YWRvcylbeF08LW5hbWVzKGhvdXNlLjEpW3hdDQp9DQpuYW1lcyhSZXN1bHRhZG9zKTwtbm9tZXMNCg0Ka25pdHI6OmthYmxlKFJlc3VsdGFkb3MsZGlnaXRzID0gMixmb3JtYXQuYXJncyA9IGxpc3Qoc2NpZW50aWZpYyA9IEZBTFNFKSwNCiAgICAgICAgICAgICBjYXB0aW9uID0gIlJlc3VtbyBkZXNjcml0aXZvIGRhcyB2YXJpw6F2ZWlzIGRlIGVzdHVkbyIpDQpgYGANCg0KOjo6IHtzdHlsZT0iY29sb3I6IHJlZCJ9DQpOdW1hIGFuw6FsaXNlIHByZWxpbWluYXIsIHBvZGUtc2UgYWZpcm1hciBhIGdyYW5kZSBhbXBsaXR1ZGUgbm9zIFByZcOnb3MNCmRlIFZlbmRhcyBkYXMgY2FzYSBlIG5vIEludGVyaW9yIGRhIENhc2EgKGZ0wrIpLiBPIGN1c3RvIG3DqWRpbyBkYXMgY2FzYXMNCm5vIHJlY29ydGUgZm9pIGRlIFVTXCQ1NDAgTWlsLlF1YW50byBhcyBjYXJhY3RlcmlzdGljYXMgZGFzIGNhc2FzLCBvIG7Cug0KZGUgYmFuaGVpcm9zIG1heGltbyByZWdpc3RyYWRvIGNvbSAzMywgY2hhbWEgYSBhdGVuw6fDo28gdmlzdG8gcXVlIGFzDQpkZW1haXMgbWVkaWRhcyBzZXBhcmF0cml6ZXMgc3VnZXJlbSBxdWUgYSBjYXNhIGNvbSBtYWlvciBudW1lcm8gZGUNCnF1YXJ0b3MgbsOjbyBzdXBlcmUgbXVpdG8gZW0gNCBxdWFydG9zLg0KOjo6DQoNCiMjIyBHcsOhZmljb3MNCg0KYGBge3J9DQojR3LDoWZpY29zIGNvbmp1Z2Fkb3MgaGlzdG9ncmFtYSBlIGJveHBsb3QNCmxheW91dChtYXQgPSBtYXRyaXgoYygxOjEyKSw0LDMsIGJ5cm93PVRSVUUpLCAgaGVpZ2h0ID0gYyhyZXAoYygwLjIsMC43KSwyKSkpDQojIGNvbnN0cnXDp8OjbyBkbyBncmlkIGRlIGltcHJlc3PDo28gMyBsaW5oYXMgeCA0IGNvbHVuYXMNCg0KZm9yIChpIGluIHNlcSgxLDQsYnk9MykpeyAjbGluaGFzIGRlIGltcHJlc3PDo28gcGFyYSBjYWRhIHBhciBkZSBncsOhZmljb3MNCg0KICBwYXIobWFyPWMoMCw0LCAwLCAxKSkgICAjbGltaXRlcyBkYXMgbWFyZ2Vuc2RvcyBib3gtcGxvdHMNCiAgZm9yIChpMiBpbiBpOihpKzIpKXsgICAgI2dlcmFuZG8gb3MgYm94LXBsb3RzDQogICAgYm94cGxvdChob3VzZS4xWyxpMl0seGxhYj1ub21lc1tpMl0sY29sPSJsaWdodCBibHVlIixvdXRjb2w9InJlZCIsDQogICAgICAgICAgICBob3Jpem9udGFsPVRSVUUsIHhheHQ9Im4iLCBmcmFtZT1GKQ0KICB9DQogIHBhcihtYXI9Yyg1LDQsMCwxKSkgICAgICNsaW1pdGVzIGRhcyBtYXJnZW5zIGRvcyBoaXN0b2dyYW1hcw0KICBmb3IoaTMgaW4gaTooaSsyKSl7ICAgICAjZ2VyYW5kbyBvcyBoaXN0b2dyYW1hcw0KICAgIGhpc3QoaG91c2UuMVssaTNdLHhsYWI9bm9tZXNbaTNdLHlsYWI9IkRlbnNpZGFkZSIsDQogICAgICAgICBtYWluPSIiLGNvbD0ibGlnaHQgYmx1ZSIscHJvYj1UUlVFKQ0KICAgIGN1cnZlKGRub3JtKHgsbWVhbihob3VzZS4xWyxpM10sIG5hLnJtPVQpLHNkKGhvdXNlLjFbLGkzXSwgbmEucm09VCkpLGFkZD1ULCBjb2w9InJlZCIpDQogIH0NCn0NCg0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KbyBwYWluZWwgZGEgY29tYmluYcOnw6NvIGRvIGhpc3RvZ3JhbWEgZSBib3gtcGxvdCwgYXByZXNlbnRhIHVtIHBhbm9yYW1hDQpnZXJhbCBkYXMgdmFyacOhdmVpcyBzZWxlY2lvbmFkYXMuIERlIG1hbmVpcmEgZ2VyYWwsIGEgcHJlc2Vuw6dhIGRlDQpjb25zaWRlcsOhdmVpcyBkZSB2YWxvcmVzIGRpc2NyZXBhbnRlcyBnYW5oYSBkZXN0YXF1ZS4gUG9yw6ltLCB0YWwgcmVzdW1vDQpncsOhZmljbyBuw6NvIHNlIG1vc3RyYSB0w6NvIGFkZXF1YWRvIHBhcmEgdmFyacOhdmVpcyBxdWFsaXRhdGl2YXMNCihjYXRlZ8OzcmljYXMpIGNvbW8gYSBWaXPDo28gZGEgUHJvcHJpZWRhZGUuIMOJIGNvbnZlbmllbnRlIHVtYSBhdmFsaWHDp8Ojbw0KZXNwZWNpZmljYSBwYXJhIHZhcmnDoXZlaXMgcXVhbnRpdGF0aXZhcyBlIHF1YWxpdGF0aXZhcy4NCjo6Og0KDQpgYGB7cn0NCiMgQm94cGxvdHMgDQpsYXlvdXQobWF0ID0gbWF0cml4KGMoMTo0KSwyLDIsIGJ5cm93PVRSVUUpLCAgaGVpZ2h0ID0gYyhyZXAoYygwLjIsMC43KSwyKSkpDQpwYXIobWZyb3c9YygyLDQpLG1hcj1jKDQsNCwzLDIpKQ0KDQpmb3IoaSBpbiAxOihsZW5ndGgoaG91c2UuMSktMikpew0KICBvdXQ8LWJveHBsb3Quc3RhdHMoaG91c2UuMVssaV0pJG91dCAjKy8tIDEuNTggSVFSL3NxcnQobikNCiAgb3V0X2luZCA8LSB3aGljaChob3VzZS4xWyxpXSAlaW4lIGMob3V0KSkNCiAgDQogIGJveHBsb3QoaG91c2UuMVssaV0seWxhYj1ub21lc1tpXSxjb2w9ImxpZ2h0IGJsdWUiLGZyYW1lPUYsIG91dGNvbD0icmVkIikNCiAgbXRleHQoIk91dGxpcmVzICgrKSIsIHNpZGU9MSxsaW5lPTAuNSwgYXQ9MC43LCBjZXggPSAwLjYpIA0KDQogIGJveHBsb3QoaG91c2UuMVstb3V0X2luZCxpXSx5bGFiPW5vbWVzW2ldLGNvbD0ibGlnaHQgYmx1ZSIsIGZyYW1lPUYpDQogIG10ZXh0KCJPdXRsaXJlcyAoIC0gKSAqIiwgc2lkZT0xLGxpbmU9MC41LCBhdD0wLjcsIGNleCA9IDAuNikgDQogIA0KICANCn0NCnBhcihvbWE9YygxLDEsMS4xLDEpLG5ldz1ULGZvbnQ9MixjZXg9MC41KQ0KbXRleHQob3V0ZXI9VFJVRSxwYXN0ZSgiQm94cGxvdHMgZGFzIHZhcmnDoXZlaXMgYXZhbGlhZGFzIiksc2lkZT0zKQ0KbXRleHQob3V0ZXI9VFJVRSxwYXN0ZSgiKiBQcmluY2lwYWlzIG91dGxpZXJzIHJlbW92aWRvcyBwZWxvIG3DqXRvZG8gZGUgSW50ZXJ2w6Fsb3MgaW50ZXJxdWFydMOtbGljbyBbKy8tMS41OCBJUVIvc3FydChuKV0iKSxzaWRlPTEsIGNleD0wLjgpDQoNCg0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KT3MgYm94LXBsb3RzIG1vc3RyYW0gYSBwcmVzZW7Dp2EgZGUgbXVpdGFzIGluZm9ybWHDp8O1ZXMgZGlzY3JlcGFudGVzLA0Kc3VnZXJpbmRvIHVtYSBhdmFsaWHDp8OjbyBtYWlzIGFwcm9mdW5kYWRhIHNvYnJlIGEgbmF0dXJlemEgZGVzdGFzIGNvbSBhDQpwb3NzaWJpbGlkYWRlIGRlIHJlbW/Dp8OjbyBvdSB0cmF0YW1lbnRvLiBObyBlbnRhbnRvLCBwYXJhIGVzdGUgZXN0dWRvLA0Kc2Vyw6NvIG1hbnRpZG9zIHRvZG9zIG9zIGRhZG9zIG9yaWdpbmFpcy4NCjo6Og0KDQpgYGB7cn0NCiNBanVzdGUgZGEgdmFyacOhdmVsIHZpc8OjbyBkYSBwcm9wcmllZGFkZQ0KaG91c2UuMTwtY2JpbmQoaG91c2UuMSx2aWV3LmY9aG91c2UuMSR2aWV3KQ0KaG91c2UuMSR2aWV3LmY8LWZhY3Rvcihob3VzZS4xJHZpZXcuZiwgbGV2ZWxzID0gYygiMCIsIjEiLCIyIiwiMyIsIjQiKSkNCg0KI0FqdXN0ZSBkYSB2YXJpw6F2ZWwgTsOtdmVsIGRlIENvbnN0cnXDp8OjbyBlIERlc2lnbg0KaG91c2UuMTwtY2JpbmQoaG91c2UuMSxncmFkZS5mPWhvdXNlLjEkZ3JhZGUpDQpob3VzZS4xJGdyYWRlLmZbKGhvdXNlLjEkZ3JhZGUgJWluJSBjKDE6MykpXTwtIkxvdyINCmhvdXNlLjEkZ3JhZGUuZlsoaG91c2UuMSRncmFkZSAlaW4lIGMoNDo2KSldPC0iTG93LU1lZCINCmhvdXNlLjEkZ3JhZGUuZlsoaG91c2UuMSRncmFkZT09NyldPC0iTWVkIg0KaG91c2UuMSRncmFkZS5mWyhob3VzZS4xJGdyYWRlICVpbiUgYyg4OjEwKSldPC0iTWVkLUhpZ2giDQpob3VzZS4xJGdyYWRlLmZbKGhvdXNlLjEkZ3JhZGUgJWluJSBjKDExOjEzKSldPC0iSGlnaCINCmhvdXNlLjEkZ3JhZGUuZjwtZmFjdG9yKGhvdXNlLjEkZ3JhZGUuZiwgbGV2ZWxzID0gYygiTG93IiwiTG93LU1lZCIsIk1lZCIsIk1lZC1IaWdoIiwgIkhpZ2giKSkNCmBgYA0KDQpgYGB7cn0NCiNncmFmaWNvcyBkYXMgdmFyaWF2ZWlzIGNhdGVnw7NyaWNhcw0KcGFyKG1mcm93ID0gYygxLDIpKQ0KDQp4PC14dGFicyh+dmlldy5mLGRhdGEgPSBob3VzZS4xKQ0KYmFycGxvdCh4LA0KICAgICAgICB5bGFiID0gIkZyZXF1w6puY2lhIGFic29sdXRhIiwNCiAgICAgICAgeGxhYiA9IG5vbWVzWzVdLA0KICAgICAgICB5bGltID0gYygwLG1heCh4KSoxLjEpLCNsaW0gc3VwIDEwJSBhKyBwLyBtYXggcGFyYSBtZWxob3IgdmlzdWFsaXphw6fDo28NCiAgICAgICAgY29sPWhjbC5jb2xvcnMobGVuZ3RoKHgpLCAiR3JlZW4tT3JhbmdlIikpDQoNCng8LXh0YWJzKH5ncmFkZS5mLGRhdGEgPSBob3VzZS4xKQ0KYmFycGxvdCh4LA0KICAgICAgICB5bGFiID0gIkZyZXF1w6puY2lhIGFic29sdXRhIiwNCiAgICAgICAgeGxhYiA9IG5vbWVzWzZdLA0KICAgICAgICB5bGltID0gYygwLG1heCh4KSoxLjEpLA0KICAgICAgICBjb2w9aGNsLmNvbG9ycyhsZW5ndGgoeCksICJSZWQtR3JlZW4iKSwNCiAgICAgICAgY2V4Lm5hbWVzID0gMC42LA0KICAgICAgICBsYXM9MykNCg0KcGFyKG9tYT1jKDEsMSwxLjEsMSksbmV3PVQsZm9udD0yLGNleD0wLjUpDQptdGV4dChvdXRlcj1UUlVFLHBhc3RlKCJHcsOhZmljb3MgZGUgQmFycmFzIGRhcyBWYXJpw6F2ZWlzIENhdGVnw7NyaWNhcyIpLHNpZGU9MykNCg0KI2dyYXkuY29sb3JzKG4pDQojaGNsLnBhbHMoKSBub21lcyBkYXMgcGFsbGV0cw0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KQXMgdmFyacOhdmVpcyBjYXRlZ8OzcmljYXMgbW9zdHJhbSBxdWUgYSBncmFuZGUgbWFpb3JpYSBkYSBwcm9wcmllZGFkZSB0ZW0NCmJhaXhvIG7DrXZlbCBuYSBxdWFsaWRhZGUgZGEgdmlzw6NvLCBhbyBwYXNzbyBxdWUgbyBuw612ZWwgZGFzIGNvbnN0cnXDp8O1ZXMNCnPDo28gcHJlZG9taW5hbnRlbWVudGUgY29uc2lkZXJhZGFzIGNvbW8gbsOtdmVsIG3DqWRpbyBvdSBtw6lkaW8tYWx0by4NCjo6Og0KDQpgYGB7cn0NCiNsaW1wYW5kbyBhIG3DqW1vcmlhDQpybShSZXN1bHRhZG9zLCBFc3REZXNjcmksb3V0LCBvdXRfaW5kLHgsaG91c2UuMSxpLGkyLGkzKQ0KYGBgDQoNCiMjIFF1ZXN0w6NvIDAyDQoNClBhcmEgYXMgdmFyacOhdmVpcyBxdWFudGl0YXRpdmFzLCBjYWxjdWxlIGEgbWF0cml6IGRlIGNvcnJlbGHDp8OjbyBlIGZhw6dhDQp1bSBncsOhY28gZW0gcXVlIHNlIHBvc3NhIGZhY2lsbWVudGUgdmlzdWFsaXphciBhcyBjb3JyZWxhw6fDtWVzIGVudHJlIGFzDQp2YXJpw6F2ZWlzLiBFbSBzZWd1aWRhLCBmYcOnYSBkaWFncmFtYXMgZGUgZGlzcGVyc8OjbyBwYXJhIG9zIGRvaXMgcGFyZXMgZGUNCnZhcmnDoXZlaXMgbWFpcyBjb3JyZWxhY2lvbmFkb3MuDQoNCiMjIyBNYXRyaXogZGUgQ29ycmVsYcOnw6NvDQoNCmBgYHtyfQ0KQ09SPC1jb3IodmVuZGFzWywtYygxLDIsMTIpXSkNCiMgS2FibGUgw6kgdW0gZ2VyYWRvciBkZSB0YWJlbGEgY29tIGZvcm1hdGHDp8OjbyBhbWlnYXZlbCBwYXJhIHNhaWRhcyBodG1sDQprbml0cjo6a2FibGUoQ09SLGRpZ2l0cyA9IDIsZm9ybWF0LmFyZ3MgPSBsaXN0KHNjaWVudGlmaWMgPSBGQUxTRSksDQogICAgICAgICAgICAgY2FwdGlvbiA9ICJDb3JyZWxhw6fDo28gZW50cmUgYXMgdmFyacOhdmVpcyBkbyBiYW5jbyBkZSBkYWRvcyIpDQpgYGANCg0KOjo6IHtzdHlsZT0iY29sb3I6IHJlZCJ9DQpBIG1hdHJpeiBlIGNvcnJlbGHDp8OjbyDDqSB1bWEgw7N0aW1hIG1hbmFpcmEgZGUgYW5hbGl6YXIgb3MgbsOtdmVpcw0KYXNzb2NpYcOnw6NvIGxpbmVhciBlbnRyZSBwYXJlcyBkZSB2YXJpw6F2ZWlzLiBQw7NlbSBtYXRpemVzIGNvbSBncmFuZGVzDQpuw7ptZXJvcyBkZSB2w6FyacOhdmVpcywgcG9kZW0gbsOjbyBzZXIgdMOjbyBjbGFyYXMuDQo6OjoNCg0KYGBge3IgZWNobz1UUlVFfQ0KI2luc3RhbGHDp8OjbyBkZSBwYWNvdGUgbmVjZXNzw6FyaW8gcGFyYSBpbHVzdHJhw6fDo28gZGEgbWF0cml6IGRlIGNvcnJlbGHDp8Ojbw0KaWYgKCFyZXF1aXJlKCJjb3JycGxvdCIpKSBpbnN0YWxsLnBhY2thZ2VzKCJjb3JycGxvdCIsIGRlcGVuZGVuY2llcyA9IFRSVUUsIElOU1RBTExfb3B0cyA9ICctLW5vLWxvY2snKQ0KbGlicmFyeShjb3JycGxvdCkNCmBgYA0KDQpgYGB7cn0NCiNpbHVzdHJhw6fDo28gZGEgbWF0cml4IGRlIGNvcnJlbGHDp8O1ZXMgZGUgbWFuZWlyYSBtYWlzIGFtaWfDoXZlbA0KY29ycnBsb3QoQ09SLCBtZXRob2QgPSAic3F1YXJlIiwgdHlwZT0idXBwZXIiKQ0Kcm0oQ09SKQ0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KTyBjb3JyZWxvZ3JhbWEgcHJvZHV6aWRvIHBlbG8gImNvcnJwbG9yIiwgZXZpZGVuY2lhIGFzc29jaWHDp8O1ZXMNCmNvbnNpZGVyw6F2ZWlzIGVudHJlOiAqcHJpY2UqIGUgYmF0aHJvb21zLCBzcWZ0X2xpdmluZywgZ3JhZGUsIHNxZnRfYWJvdmUNCmUgc3FmdF9sb3QxNTsgKnNxZnRfbGl2aW5nKiBlIGdyYWRlLCBzcWZ0X2Fib3ZlIGUgc3FmdF9sb3QxNS4gQXMNCnZhcmnDoXZlaXMgcXVlIHJlcHJlc2VudGFtIMOhcmVhcyB0ZW0gYWx0b3Mgbml2ZWlzIGRlIGFzc29jaWHDp8OjbywgcG9pcw0KYWxndW1hcyBkZWxhcyBzw6NvIGNvbXBvc2nDp8OjbyBkZSBvdXRyYXMuIERlc3RhIGZvcm1hLCBlc3RhcyB2YXJpw6F2ZWlzDQpwb2RlbSBzZXIgY29uc2lkZXJhZGFzIGF1dG9jb3JyZWxhY2lvbmFkYXMuDQo6OjoNCg0KIyMjIEdyw6FmaWNvcw0KDQpgYGB7cn0NCiMgcGFyIGRlIG1haW9yIGNvcnJlbGHDp8Ojbw0KcGxvdChzcWZ0X2xpdmluZyB+IHNxZnRfYWJvdmUsDQogICAgIGRhdGEgID0gdmVuZGFzLA0KICAgICBtYWluID0gIkRpc3ByZXNzw6NvIFxuIEludGVyaW9yIGRhIGNhc2EgWCBJbnRlcmlvciBkYSBjYXNhIGFjaW1hIGRvIG7DrXZlbCBkbyBzb2xvICIsDQogICAgIGNleC5tYWluID0gMC45LA0KICAgICB4bGFiID0gIkludGVyaW9yIGRhIGNhc2EgYWNpbWEgZG8gbsOtdmVsIGRvIHNvbG8gKGZ0wrIpIiwNCiAgICAgeWxhYiA9ICJJbnRlcmlvciBkYSBjYXNhIChmdMKyKSIsDQogICAgIHhsaW0gPSBjKDAsMTQwMDApLA0KICAgICBwY2ggID0gMjEsDQogICAgIGNleCAgPSAwLjgsDQogICAgIGNvbCAgPSAiYmxhY2siLA0KICAgICBiZyAgID0gImdyYXkiLA0KICAgICBmcmFtZT0gRkFMU0UpDQpncmlkKCkNCmFibGluZShjb2VmID0gYygwLDEpLCBjb2w9InJlZCIpDQpgYGANCg0KOjo6IHtzdHlsZT0iY29sb3I6IHJlZCJ9DQpPIGdyw6FmaWNvIGFjaW1hIG1vc3RyYSBhIGRpc3BlcnNzw6NvIGRvcyBkYWRvcyBlbnRyYSBhcyBkdWFzIHZhcmlhdmFpcyBkZQ0KbWFpb3IgY29ycmVsYcOnw6NvOiAqYSDDoXJlYSBkbyBJbnRlcmlvciBkYSBjYXNhIGFjaW1hIGRvIG7DrXZlbCBkbyBzb2xvDQooZnTCsikqIGUgKkludGVyaW9yIGRhIGNhc2EgKGZ0wrIpKi4gQSBkaWFnb25hbCB0cmHDp2FkYSBlbSB2ZXJtZWxobywNCm1vc3RyYSBxdWUgYSByZWxhw6fDo28gaW50ZXJpb3IvYWNpbWEgc2Vyw6EgcGVsbyBtZW5vcyAxLiAtIEFzIGNvbnN0cnXDp8O1ZXMNCnBsb3RhZGFzIHNvYnJlIGEgZGlhZ29uYWwgbW9zdHJhIHF1ZSB0b2RhIGEgY29uc3RydcOnw6NvIGVzdMOhIGFjaW1hIGRvDQpzb2xvIGUgbsOjbyB0ZW1kbyBuYWRhIGNvbnN0cnXDrWRvIGFiYWl4byBkbyBzb2xvOyAtIFF1YW50byBtYWlzIGFmYXN0YWRvDQpvIHBvbnRvIGFjaW1hIGRhIGRpYWdvbmFsIHNlIGFmYXN0YSBkZWxhIG1haW9yIGEgw6FyZWEgY29udHJ1w61kYSBubw0Kc3Vic29sbzsgLSBOZW5odW1hIGNvbnN0cnXDp8OjbyDDqSB0b3RhbG1lbnRlIG5vIHN1YnNvbG8uDQo6OjoNCg0KIyMgUXVlc3TDo28gMDMNCg0KVmVyaWZpcXVlIGdyYWZpYW1lbnRlIGEgYXNzb2NpYcOnw6NvIGVudHJlIG8gcHJlw6dvIGUgcGVsbyBtZW5vcyB0csOqcw0Kb3V0cmFzIHZhcmnDoXZlaXMgZG8gYmFuY28gZGUgZGFkb3MuIEludmVzdGlndWUgYSBtZWxob3IgZm9ybWEgZGUNCnZpc3VhbGl6YcOnw6NvOiBncsOhY28gZGUgZGlzcGVyc8OjbywgKmJveC1ibG90cyouDQoNCiMjIyBEaXNwZXJzc8OjbzogUHJlw6dvIFggSW50ZXJpb3IgZGEgQ2FzYSAoYnkgQmVpcmEtbWFyKQ0KDQpgYGB7cn0NCiNEaXNwZXJzc8OjbyAwMQ0KY29sczwtaGNsLmNvbG9ycyhsZW5ndGgobGV2ZWxzKGFzLmZhY3Rvcih2ZW5kYXMkd2F0ZXJmcm9udCkpKSwgIkdyZWVuLU9yYW5nZSIpDQogIA0KcGxvdChwcmljZS8xMDAwIH4gc3FmdF9saXZpbmcsDQogICAgIGRhdGEgPSB2ZW5kYXMsDQogICAgIG1haW4gPSAiUHJlw6dvIFggSW50ZXJpb3IgZGEgQ2FzYSBcbiAoYnkgQmVpcmEtbWFyKSIsDQogICAgIHhsYWIgPSAiSW50ZXJpb3IgZGEgY2FzYSAoZnTCsikiLA0KICAgICB5bGFiID0gIlByZcOnbyAoVVMkICoxLjAwMCkiLA0KICAgICBjZXgubWFpbiA9IDAuOSwNCiAgICAgYmcgPSBjb2xzLA0KICAgICBwY2ggPSAyMSwNCiAgICAgY2V4PTAuOCwNCiAgICAgZnJhbWU9IEYpDQoNCmxlZ2VuZCgidG9wIiwNCiAgICAgICBwY2ggPSAyMSwNCiAgICAgICBsdHkgPSAwLA0KICAgICAgIGNvbCA9ICJibGFjayIsDQogICAgICAgcHQuYmcgPSBjb2xzLA0KICAgICAgIGxlZ2VuZCA9IGMoIk91dHJvcyBsb2NhaXMiLCJCYWlyYS1tYXIiKSwNCiAgICAgICBidHkgPSAibiIpDQpncmlkKCkNCnJtKGNvbHMpDQpgYGANCg0KOjo6IHtzdHlsZT0iY29sb3I6IHJlZCJ9DQrDiSBwb3Nzw612ZWwgb2JzZXJ2YXIgdW1hIHJlbGHDp8OjbyBwb3NpdGl2YSBlbnRyZSBvIHByZcOnbyBkZSB2ZW5kYSBlIG8NCmludGVyaW9yIGRhIGNhc2EuIE5vIGVudGFudG8sIG7Do28gw6kgcG9zc8OtdmVsIHZpc3VhbGl6YXIgYWxndW1hIHJlbGHDp8Ojbw0KZW50cmUgZWxhcyBlIGEgcG9zacOnw6NvIGRhIGNvbnN0cnXDp8OjbyBhIGJlaXJhLW1hci4NCjo6Og0KDQojIyMgRGlzcGVyc3PDo286IFByZcOnbyBYIE7Dum1lcm8gZGUgUXVhcnRvcyAoYnkgQ29uZGnDp8OjbyBkbyBBcGFydGFtZW50bykNCg0KYGBge3J9DQojRGlzcGVyc3PDo28gMDENCmNvbHM8LWhjbC5jb2xvcnMobGVuZ3RoKGxldmVscyhmYWN0b3IodmVuZGFzJGNvbmRpdGlvbikpKSwgImluZmVybm8iKQ0KICANCnBsb3QocHJpY2UvMTAwMCB+IGJlZHJvb21zLA0KICAgICBkYXRhID0gdmVuZGFzLA0KICAgICBtYWluID0gIlByZcOnbyBYIE7CuiBkZSBRdWFydG9zIFxuIChieSBDb25kacOnw6NvIGRvIEFwYXJ0YW1lbnRvKSIsDQogICAgIHhsYWIgPSAiTsK6IGRlIFF1YXJ0b3MiLA0KICAgICB5bGFiID0gIlByZcOnbyAoVVMkICoxLjAwMCkiLA0KICAgICBjZXgubWFpbiA9IDAuOSwNCiAgICAgYmcgPSBjb2xzLA0KICAgICBwY2ggPSAyMSwNCiAgICAgY2V4PTAuOCwNCiAgICAgZnJhbWU9IEYpDQpsZWdlbmQoInRvcCIsDQogICAgICAgcGNoID0gMjEsDQogICAgICAgbHR5ID0gMCwNCiAgICAgICBjb2wgPSAiYmxhY2siLA0KICAgICAgIHB0LmJnID0gY29scywNCiAgICAgICBsZWdlbmQgPSBsZXZlbHMoZmFjdG9yKHZlbmRhcyRjb25kaXRpb24pKSwNCiAgICAgICBidHkgPSAibiIpDQpncmlkKCkNCnJtKGNvbHMpDQpgYGANCg0KOjo6IHtzdHlsZT0iY29sb3I6IHJlZCJ9DQpBIGRpc3BlcnNzw6NvIGRlIHByZcOnbyBkZSB2ZW5kYSB4IG7CuiBkZSBxdWFydG9zIGFzc29jaWFkYSBhIGNvbmRpw6fDo28gZGENCkNvc250cnXDp8OjbyBuw6NvIG1vc3RyYSBuaGVudW1hIHJlbGHDp8OjbyBlbnRyZSBlbGFzIC4NCjo6Og0KDQojIyMgQm94LVBsb3QNCg0KYGBge3J9DQp4PC0gZGF0YS5mcmFtZShJbmRpY2U9Yyg0LDUsMTAsMTMsOSksTm9tZXM9KGMobm9tZXNbYygyLDMsNSw2KV0sIkJlaXJhLU1hciIpKSkNCnBhcihtZnJvdyA9IGMoMiwzKSkNCg0KZm9yKGkgaW4gMTpsZW5ndGgoeCRJbmRpY2UpKXsNCiAgYm94cGxvdCgodmVuZGFzJHByaWNlLzEwMDApIH4gdmVuZGFzWyx4JEluZGljZVtpXV0sDQogICAgICAgICAgeGxhYiA9IHgkTm9tZXNbaV0sDQogICAgICAgICAgeWxhYiA9ICJQcmXDp28gZGUgVmVuZGEgKFVTJCB4MS4wMDApIiwNCiAgICAgICAgICBjb2wgID0gImxpZ2h0IGJsdWUiLA0KICAgICAgICAgIGZyYW1lID0gRkFMU0UsIA0KICAgICAgICAgIG91dGNvbD0gInJlZCIpDQp9DQpybSh4KQ0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KQXMgZGlzdHJpYnVpw6fDtWVzIGRvcyBwcmXDp29zIHBvciBncnVwb3MgZGFzIHZhcmnDoXZlaXMgbmFzIHJlcHJlc2VudGHDp8O1ZXMNCmRvcyBib3gtcGxvdCwgc2VkbyBwb3Nzw612ZWwgbm90YXIgb21hIHJlbGHDp8OjbyBwb3NpdGl2YSBlbnRyZSBvIHByZcOnbyBlDQphcyBtZWRpYW5hcyBkb3MgZ3J1cG9zIGRhIHZhcmnDoXZlaXMuDQo6OjoNCg0KIyMgUXVlc3TDo28gMDQNCg0KQWdydXBlIG9zIGRhZG9zIHBvciBkYXRhIChtw6pzIGUgYW5vKSBlIGNhbGN1bGUgYSBtw6lkaWEgZG8gcHJlw6dvIHBhcmENCmNhZGEgbcOqcy4gRW0gc2VndWlkYSwgZmHDp2EgdW0gZ3LDoWZpY28gZGUgbGluaGEgY29tIGEgdmFyaWHDp8OjbyBkbyBwcmXDp28NCmFvIGxvbmdvIGRvIHRlbXBvLg0KDQpBIHBhcnRpciBkb3MgcHJlw6dvcyBlIHDDqXMgcXVhZHJhZG9zIGRvIGludGVyaW9yIGRhIGNhc2EsIGNhbGN1bGUsIHBhcmENCmNhZGEgcmVnaXN0cm8sIG8gcHJlw6dvIG3DqWRpbyBkbyBww6kgcXVhZHJhZG8uIEVtIHNlZ3VpZGEsIGZhw6dhIHVtIGdyw6Fjbw0KZGUgbGluaGEgY29tIGEgdmFyaWHDp8OjbyBkbyBwcmXDp28gbcOpZGlvIGFvIGxvbmdvIGRvIHRlbXBvLg0KDQojIyMgUHJlcGFyYcOnw6NvIGUgQWp1c3Rlcw0KDQpgYGB7ciByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCiMgaW5zdGFsYcOnw6NvIGRlIHBhY290ZXMgcGFyYSBjcmlhw6fDo28gZGUgZ3LDoWZpY28gdGVtcG9yYWwNCg0KLnBhY2thZ2VzID0gYygiZHlncmFwaHMiLCAieHRzIikjIExpc3RhIGRlIGJpYmxpb3RlY2FzIG5lY2Vzc8Ohcmlhcw0KDQojIEluc3RhbGFyIChjYXNvIGFpbmRhIG7Do28gdGVuaGEgc2lkbyBpbnN0YWxhZG8pDQouaW5zdCA8LSAucGFja2FnZXMgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKQ0KaWYobGVuZ3RoKC5wYWNrYWdlc1shLmluc3RdKSA+IDApIGluc3RhbGwucGFja2FnZXMoLnBhY2thZ2VzWyEuaW5zdF0sZGVwZW5kZW5jaWVzID0gVFJVRSkNCg0KIyBDYXJyZWdhbmRvIGJpYmxpb3RlY2FzDQpsYXBwbHkoLnBhY2thZ2VzLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seT1UUlVFKQ0KDQpgYGANCg0KIyMjIFByZcOnb3MgZGUgVmVuZGEgcG9yIERhdGENCg0KYGBge3J9DQojQXJ1cGFuZG8gYSBtw6lkaWEgZG8gcHJlw6dvIGRlIHZlbmRhIHBvciBkYXRlMigpIA0KeCA8LSBhZ2dyZWdhdGUodmVuZGFzJHByaWNlLzEwMDAsIGJ5ID0gbGlzdCh2ZW5kYXMkZGF0ZTIpLCBGVU49bWVhbikNCg0KI2NyaWFuZG8gYSBzZXF1ZW5jaWEgZGUgZGF0YXMgcGFyYSBhdXhpbGlhciBubyBncsOhZmljby4NCnggPC1jYmluZCh4LHRpbWU9c2VxKGZyb209IGFzLkRhdGUoIjAxLzA1LzIwMTQiLCIlZC8lbS8lWSIpLA0KICAgICAgICAgICAgICAgICAgICAgdG8gID0gYXMuRGF0ZSgiMDEvMDUvMjAxNSIsIiVkLyVtLyVZIiksDQogICAgICAgICAgICAgICAgICAgICBieSAgPSAibW9udGgiKSkNCg0KIyBOZWNlc3PDoXJpbyB0cm5hc2Zvcm1hciBlbSBmb3JtYXRvICJ4dHMiIHBhcmEgcG9kZXIgdXNhciBvIGR5Z3JhcGgNCmdyYWYgPC0geHRzKHggPSB4JHgsIG9yZGVyLmJ5ID0geCR0aW1lKQ0KDQpkeWdyYXBoKGdyYWYsDQogICAgICAgIG1haW49IkNvbXBvcnRhbWVudG8gZGEgTcOpZGlhIGRlIFByZcOnb3MgZGUgVmVuZGEiLA0KICAgICAgICB5bGFiPSJQcmXDp29zIGRlIFZlbmRhIChVUyQgKjEuMDAwKSIsDQogICAgICAgIHhsYWI9Ik1lc2VzIikNCnJtKHgsZ3JhZikNCmBgYA0KDQo6Ojoge3N0eWxlPSJjb2xvcjogcmVkIn0NCkEgbcOpZGlhIGRlIHByZcOnb3MgZG9zIGltw7N2ZWlzIHRldmUgdW0gY29tcG9ydGFtZW50ZSBkZSBxdWVkYSBhdMOpDQpmZXYvMjAxNSwgcXVhbmRvIHJldG9tb3UgdW1hIHN1YmlkYSBtdWl0byByw6FwaWRhLg0KOjo6DQoNCiMjIyBQcmXDp28gTcOpZGlvIHBvciBmdMKyIGRvIEludGVyaW9yIGRhIENhc2ENCg0KYGBge3J9DQojIGNyaWFuZG8gdmFyacOhdmVsIHByZcOnbyBwb3IgZnTCsiBjb25zdHLDrWRhDQp2ZW5kYXMgPC0gY2JpbmQodmVuZGFzLCBwcmljZV9mdDIgPSAodmVuZGFzJHByaWNlL3ZlbmRhcyRzcWZ0X2xpdmluZykpDQpgYGANCg0KYGBge3J9DQojQXJ1cGFuZG8gYSBtw6lkaWEgZG8gcHJlw6dvL2Z0wrIgZGF0ZTIoKSANCnggPC0gYWdncmVnYXRlKHZlbmRhcyRwcmljZV9mdDIsIGJ5ID0gbGlzdCh2ZW5kYXMkZGF0ZTIpLCBGVU49bWVhbikNCg0KI2NyaWFuZG8gYSBzZXF1ZW5jaWEgZGUgZGF0YXMgcGFyYSBhdXhpbGlhciBubyBncsOhZmljby4NCnggPC1jYmluZCh4LHRpbWU9c2VxKGZyb209IGFzLkRhdGUoIjAxLzA1LzIwMTQiLCIlZC8lbS8lWSIpLA0KICAgICAgICAgICAgICAgICAgICAgdG8gID0gYXMuRGF0ZSgiMDEvMDUvMjAxNSIsIiVkLyVtLyVZIiksDQogICAgICAgICAgICAgICAgICAgICBieSAgPSAibW9udGgiKSkNCg0KIyBOZWNlc3PDoXJpbyB0cm5hc2Zvcm1hciBlbSBmb3JtYXRvICJ4dHMiIHBhcmEgcG9kZXIgdXNhciBvIGR5Z3JhcGgNCmdyYWYgPC0geHRzKHggPSB4JHgsIG9yZGVyLmJ5ID0geCR0aW1lKQ0KDQpkeWdyYXBoKGdyYWYsDQogICAgICAgIG1haW49IkNvbXBvcnRhbWVudG8gZGEgTcOpZGlhIGRlIFByZcOnb3MvZnTCsiBkbyBJbnRlcmlvciBkYSBDYXNhIiwNCiAgICAgICAgeWxhYj0iUHJlw6dvcyBkZSBWZW5kYS9mdMKyIiwNCiAgICAgICAgeGxhYj0iTWVzZXMiKQ0Kcm0oeCxncmFmKQ0KYGBgDQoNCjo6OiB7c3R5bGU9ImNvbG9yOiByZWQifQ0KbyBwcmXDp28gbcOpZGlvIHBvciBmdMKyIHRlbSB1bSBtb3ZpbWVudG8gc3VhdmUgZGUgcXVlZGEgbm8gcGVyaW9kbyBkZQ0KTWFpLzIwMTQgYSBEZXovMjAxNCwgb25kZSBmb2kgcmVnaXN0cmFkbyBvIG1lbm9yIHBhdGFtYXIgZG8gcHJlw6dvLiBBDQpwYXJ0aXIgZGUgZW50w6NvIHVtIGNvbXBvcnRhbWVudG8gZGUgdmFsb3JpemHDp8OjbyByw6FwaWRhIHN1cGVyYW5kbyBvcw0KcGF0YW1hcmVzIGFudGVyaW9lcyBubyAzwrogbWVzIHN1YmlkYS4NCjo6Og0KDQojIyBRdWVzdMOjbyAwNQ0KDQpDYWxjdWxlIG9zIHF1YXJ0aXMgZG8gcHJlw6dvICh2YWxvcmVzIHF1ZSBkaXZpZGVtIG9zIHByZcOnb3MgZW0gcXVhdHJvDQpmYWl4YXMsIGNhZGEgdW0gY29tIDI1JSBkb3MgcmVnaXN0cm9zKS4gVmVyaWZpcXVlIGVtIHF1ZSBmYWl4YSBjYWRhDQpwcmXDp28gZG8gYmFuY28gZGUgZGFkb3Mgc2UgZW5jb250cmEgZSBhc3NvY2llIGEgZWxlIHVtIGNvciBkaWZlcmVudGUuIEVtDQpzZWd1aWRhLCBmYcOnYSB1bSBncsOhY28gZW0gdHLDqnMgZGltZW5zw7VlcyBjb20gYSBsYXRpdHVkZSwgbG9uZ2l0dWRlIGUgbw0KcHJlw6dvIChjb20gYXMgY29yZXMgY29ycmVzcG9uZGVudGVzIMOgIHN1YSByZXNwZWN0aXZhIGZhaXhhKS4NCg0KIyMjIFByZXBhcmHDp8OjbyBlIEFqdXN0ZXMNCg0KYGBge3IgZWNobz1GQUxTRX0NCiMgaW5zdGFsYcOnw6NvIGRlIHBhY290ZXMgcGFyYSBjcmlhw6fDo28gZGUgZ3LDoWZpY28gM2QNCmlmICghcmVxdWlyZSgic2NhdHRlcnBsb3QzZCIpKSBpbnN0YWxsLnBhY2thZ2VzKCJzY2F0dGVycGxvdDNkIiwgZGVwZW5kZW5jaWVzID0gVFJVRSwgSU5TVEFMTF9vcHRzID0gJy0tbm8tbG9jaycpDQpsaWJyYXJ5KCJzY2F0dGVycGxvdDNkIikNCmBgYA0KDQpgYGB7cn0NCiMgY2xhc3NpZmljYcOnw6NvIGRvcyBxdWFydGlzIGRlIHByZcOnb3MgZGUgdmVuZGENCnZlbmRhczwtY2JpbmQodmVuZGFzLA0KICAgICAgICAgICAgICBwcmljZS5xID0gd2l0aCh2ZW5kYXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1dChwcmljZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHF1YW50aWxlKHByaWNlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnM9c2VxKDAsMSwgYnk9MC4yNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IDE6NCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0PVRSVUUpKSkNCmBgYA0KDQojIyMgR3LDoWZpY28gM0QgRXN0w6F0aWNvDQoNCmBgYHtyfQ0KI1NjYXRlcnBsb3QgM0QNCg0KI1BhbGV0YSBkZSBjb3Jlcw0KY29sczwtaGNsLmNvbG9ycyhsZW5ndGgobGV2ZWxzKHZlbmRhcyRwcmljZS5xKSksICJQdU9yIikNCg0Kd2l0aCh2ZW5kYXMsew0KICBzY2F0dGVycGxvdDNkKGxhdCxsb25nLHByaWNlLzEwMDAsDQogICAgICAgICAgICAgICAgbWFpbiA9ICIzLUQgU2NhdGVycGxvdCIsDQogICAgICAgICAgICAgICAgeGxhYj0iTGF0aXR1ZGUiLA0KICAgICAgICAgICAgICAgIHpsYWI9IlByZcOnbyBkZSBWZW5kYSAoVVMkIHgxLjAwMCkiLA0KICAgICAgICAgICAgICAgIHlsYWI9IkxvbmdpdHVkZSIsDQogICAgICAgICAgICAgICAgdHlwZT0icCIsDQogICAgICAgICAgICAgICAgbHR5LmhwbG90PTIsDQogICAgICAgICAgICAgICAgc2NhbGUueT0uNSwNCiAgICAgICAgICAgICAgICBib3g9VCwNCiAgICAgICAgICAgICAgICBjb2xvcj1jb2xzW3ByaWNlLnFdLA0KICAgICAgICAgICAgICAgIHBjaD0xNiwNCiAgICAgICAgICAgICAgICBhbmdsZT00NSkNCn0pDQpgYGANCg0KOjo6IHtzdHlsZT0iY29sb3I6IHJlZCJ9DQpBIGRpc3BlcnPDo28gZW0gMyBkaW1lbnPDtWVzIGFwcmVzZW50YSB1bWEgdmlzdWFsaXphw6fDo28gcGxhbm9zIG5hIG1hbGhhIGRlDQpsYXRpdHVkZSBlIGxvZ2l0dWRlIHBhcmEgY2FkYSBuw612ZWwgZG9zIHF1YXJ0aXMgZG9zIHByZcOnb3MgZGUgdmVuZGFzLg0KRXN0ZXMgcGxhbm9zIHBvZGVyaWFtIHNlciBtYWlzIGJlbSBpZGVudGlmaWNhZG9zIGNvbSBvIGlzb2xhbWVudG8gZG9zDQptYWlvcmVzIHByZcOnb3MsIG9zIHF1YWlzIGRpc3RvcmNlbSBvIGVpeG8gY2F1c2FuZG8gdW1hIHNvYnJlcG9zacOnw6NvDQp2aXN1YWwgZG9zIHBvbnRvcy4NCjo6Og0KDQojIyMgR3LDoWZpY28gM0QgSW50ZXJhdGl2bw0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KaWYgKCFyZXF1aXJlKCJyZ2wiKSkgaW5zdGFsbC5wYWNrYWdlcygicmdsIiwgZGVwZW5kZW5jaWVzID0gVFJVRSwgSU5TVEFMTF9vcHRzID0gJy0tbm8tbG9jaycpDQpsaWJyYXJ5KHJnbCkNCm9wdGlvbnMocmdsLnVzZU5VTEw9VFJVRSkgI0ltcGVkaXIgcXVlIHVtYSBub3ZhIGphbmVsYSBzZWphIGNyaWFkYQ0KYGBgDQoNCmBgYHtyfQ0KIyBSZXRpcmFkYSBkZSB1bWEgYW1vc3RyYSBhbGVhdMOzcmlhIGRlIDEwMDAgY2FzYXMgcGFyYSBpbHVzdHJhciBvIGdyYWZpY28gaW50ZXJhdGl2byANCnZlbmRhcy4xPC12ZW5kYXNbc2FtcGxlKDE6bnJvdyh2ZW5kYXMpLDEwMDAscmVwbGFjZT1GKSxdDQoNCmNvbHM8LWhjbC5jb2xvcnMobGVuZ3RoKGxldmVscyh2ZW5kYXMkcHJpY2UucSkpLCAiUHVPciIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgR3JhZmljbyBpbnRlcmF0aXZvIHNpbXBsZXMNCnBsb3RpZHMgPC0gd2l0aCh2ZW5kYXMuMSwgcGxvdDNkKGxhdCxsb25nLChwcmljZS8xMDAwKSwNCiB0eXBlPSJzIiwgY29sPWNvbHNbcHJpY2UucV0sc2l6ZT0xKSkNCnJnbHdpZGdldChlbGVtZW50SWQgPSAicGxvdDNkcmdsIikNCmBgYA0KDQpgYGB7cn0NCiNncmFmaWNvIGludGVyYXRpdm8gbWFpcyBlbGFib3JhZG8gY29tIGEgcG9zc2liaWxpZGFkZSBkZSBleGliacOnw6NvIGRvcyBlbGVtZW50b3MNCmNsZWFyM2QoKSAjIFJlbW92ZSB0aGUgZWFybGllciBkaXNwbGF5DQojcm0oYXhlc2lkKQ0KIyBDaXJhw6fDo28gZG9zIGVsZW1lbnRvcyBwYXJhIG8gb2JqZXRvIGdyYWZpY28zZCBkZSBhY29yZG8gY29tIG9zIGVsZW1lbnRvcyBkYSBiaWJsaW90ZWNhIHJnbA0KUTEgPC0gd2l0aChzdWJzZXQodmVuZGFzLjEsIHByaWNlLnEgPT0gMSksDQogICAgICAgICAgIHNwaGVyZXMzZChsYXQsbG9uZywocHJpY2UvMTAwMCksDQogICAgICAgICAgICAgICAgICAgICBjb2w9Y29sc1twcmljZS5xXSwNCiAgICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDUwKSkNCg0KUTIgPC0gd2l0aChzdWJzZXQodmVuZGFzLjEsIHByaWNlLnEgPT0gMiksDQogICAgICAgICAgIHNwaGVyZXMzZChsYXQsbG9uZywocHJpY2UvMTAwMCksDQogICAgICAgICAgICAgICAgICAgICBjb2w9Y29sc1twcmljZS5xXSwNCiAgICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDUwKSkNCg0KUTMgPC0gd2l0aChzdWJzZXQodmVuZGFzLjEsIHByaWNlLnEgPT0gMyksDQogICAgICAgICAgIHNwaGVyZXMzZChsYXQsbG9uZywocHJpY2UvMTAwMCksDQogICAgICAgICAgICAgICAgICAgICBjb2w9Y29sc1twcmljZS5xXSwNCiAgICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDUwKSkNCg0KUTQgPC0gd2l0aChzdWJzZXQodmVuZGFzLjEsIHByaWNlLnEgPT0gNCksDQogICAgICAgICAgIHNwaGVyZXMzZChsYXQsbG9uZywocHJpY2UvMTAwMCksDQogICAgICAgICAgICAgICAgICAgICBjb2w9Y29sc1twcmljZS5xXSwNCiAgICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IDUwKSkNCg0KI2NyaWFuZG8gbyBvYmpldG8gZ3JhZmljbzNkLCBjcmlhZG8gcG9yIHBsb3QzZCBvdSBkZWNvcmF0ZTNkDQpheGVzaWQgPC0gZGVjb3JhdGUzZCh4bGFiID0gIkxhdGl0dWRlIiwgeWxhYiA9ICJMb2dpdHVkZSIsIHpsYWIgPSAiUHJlw6dvICh4MS4wMDApIikNCg0KI2luY2x1aW5kbyBvcyBlbGVtZW50b3Mgbm8gb2JqZXRvIGdyYWZpY28zZA0Kcmdsd2lkZ2V0KCkgJT4lIA0KdG9nZ2xlV2lkZ2V0KGlkcyA9IFExKSAlPiUNCnRvZ2dsZVdpZGdldChpZHMgPSBRMikgJT4lDQp0b2dnbGVXaWRnZXQoaWRzID0gUTMpICU+JQ0KdG9nZ2xlV2lkZ2V0KGlkcyA9IFE0KSAlPiUNCnRvZ2dsZVdpZGdldChpZHMgPSBheGVzaWQpICU+JSANCmFzUm93KGxhc3QgPSA1KSANCiNuw7ptZXJvIGUgb2JqZXRvcyBhIHNlcmVtIGFwcmVzZW50YWRvcyByZWNvbWVuZG8gcXVlIHNlamEgbGFzdD1uwrogZGUgZWxlbWVudG9zIHRvZ2dsZVdpbmdldA0KI2Fzc2ltIHNlcsOhIGFwcmVzZW50YWRvIGVtIHVtYSBsaW5oYSBhYmFpeG8gZG8gZ3LDoWZpY28NCmBgYA0KDQojIyMgTWFwYSAtIHBvaW5zIGdyb3VwIFF1YXRpbChQcmljZSkNCg0KYGBge3J9DQpsaWJyYXJ5KGxlYWZsZXQpDQpjb2xzPC1jKCJvcmFuZ2UiLCAibGlnaHRncmVlbiIsICJsaWdodGJsdWUiLCAicHVycGxlIikNCg0KdmVuZGFzLjE8LWNiaW5kKHZlbmRhcy4xLEhvdXNlPXBhc3RlKCJIb3VzZSAiLGMoMTpkaW0odmVuZGFzLjEpWzFdKSkpDQoNCnByaW50TW9uZXkgPC0gZnVuY3Rpb24oeCl7DQogIGZvcm1hdCh4LCBkaWdpdHM9MTAsIG5zbWFsbD0yLCBkZWNpbWFsLm1hcms9IiwiLCBiaWcubWFyaz0iLiIpDQp9DQoNCmljb25lIDwtIGF3ZXNvbWVJY29ucygNCiAgaWNvbiA9ICdob21lJywNCiAgaWNvbkNvbG9yID0gIndoaXRlIiwNCiAgbGlicmFyeSA9ICdpb24nLA0KICBtYXJrZXJDb2xvciA9IGNvbHNbdmVuZGFzLjEkcHJpY2UucV0NCikNCg0KDQpsZWFmbGV0KHZlbmRhcy4xKSAlPiUgDQogIGFkZFRpbGVzKCkgJT4lIA0KICBhZGRBd2Vzb21lTWFya2Vycyhwb3B1cCA9IHdpdGgodmVuZGFzLjEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCI8Yj5QcmXDp286IFVTJDwvYj4iLHByaW50TW9uZXkocHJpY2UpLCI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxiPkJhbmhlaXJvczogPC9iPiIsYmF0aHJvb21zLCI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxiPlF1YXJ0b3M6IDwvYj4iLGJlZHJvb21zKSksDQogICAgICAgICAgICAgaWNvbj1pY29uZSwNCiAgICAgICAgICAgICBsYWJlbD0gfkhvdXNlKQ0KYGBgDQoNCiMjIyBNYXBhIC0gQ2x1c3RlcnMgUXVhcnRpbCBkb3MgUHJlw6dvcw0KDQpgYGB7cn0NCnZlbmRhcy4yPC1jYmluZCh2ZW5kYXMuMSwNCiAgICAgICAgICAgICAgcHJpY2UucXEgPSB3aXRoKHZlbmRhcy4xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXQocHJpY2UvMTAwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHF1YW50aWxlKHByaWNlLzEwMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icz1zZXEoMCwxLCBieT0wLjI1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2xhYmVscyA9IDE6NCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0PVRSVUUpKSkNCg0KdmVuZGFzLmRmIDwtIHNwbGl0KHZlbmRhcy4yLCB2ZW5kYXMuMiRwcmljZS5xcSkNCg0KbCA8LSBsZWFmbGV0KCkgJT4lIGFkZFRpbGVzKCkNCg0KbmFtZXModmVuZGFzLmRmKSAlPiUNCiAgcHVycnI6OndhbGsoIGZ1bmN0aW9uKGRmKSB7DQogICAgbCA8PC0gbCAlPiUNCiAgICAgIGFkZE1hcmtlcnMoZGF0YT12ZW5kYXMuZGZbW2RmXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxuZz1+bG9uZywgbGF0PX5sYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPX5wcmljZS5xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1cCA9IHdpdGgodmVuZGFzLmRmW1tkZl1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIjxiPlByZcOnbzogVVMkPC9iPiIscHJpbnRNb25leSh+cHJpY2UpLCI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGI+QmFuaGVpcm9zOiA8L2I+Iix+YmF0aHJvb21zLCI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGI+UXVhcnRvczogPC9iPiIsfmJlZHJvb21zKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMocmVtb3ZlT3V0c2lkZVZpc2libGVCb3VuZHMgPSBGKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKG5vSGlkZSA9IEYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gJ2F1dG8nKSkNCiAgfSkNCg0KbCAlPiUNCiAgYWRkTGF5ZXJzQ29udHJvbCgNCiAgICBvdmVybGF5R3JvdXBzID0gbmFtZXModmVuZGFzLmRmKSwNCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpDQogICkNCmBgYA0K